Lamda Expressions

man soup·2020년 6월 11일
0

자바 문법

목록 보기
7/15

Lamda Expressions

  • 익명 클래스의 문제점은 만약 익명 클래스의 구현이 매우 단순할 경우( 예를 들어 하나의 함수만 가지고 있는 인터페이스) 익명 클래스의 syntax가 애매모호해 보일 수 있다. 이러한 경우 보통 funtionality를 아규먼트로서 다른 함수에 넣으려고 하는데 람다 표현식이 이것(functionality를 함수 아규먼트로, 코드를 데이터로서 사용하는 것)을 가능하게 한다.

Specify Search Criteria Code with a Lambda Expression

  • functional interface란 하나의 추상 메소드만을 가진 인터페이스를 말한다.

    • 하나 이상의 default 메소드 또는 static 메소드는 가지고 있을 수 있다.
  • functional 인터페이스는 하나의 추상 메소드만을 가지기 때문에 구현할 때 그 메소드의 이름을 생략해도 된다.

    • 생략하기 위해 익명 클래스 expression이 아닌 lamda expression을 사용한다.
  • standard functional interface를 사용하므로 코드사용을 더욱 줄일 수 있다.

Use Standard Functional Interfaces with Lambda Expressions

  • 하나의 간단한 abstract 메소드만 가진 functional 인터페이스는 너무 간단해 어플리케이션에서 정의할 가치가 없을 수 있다.
  • 결과적으로 JDK는 여러개의 standard functional interface를 java.util.function에 정의하고있다.
  • 예를 들어 Predicate 인터페이스는 boolean을 return하는 test 메소드를 가지고 있다.

Syntax of Lambda Expressions

A lambda expression consists of the following:

  • lamda expression은 다음을 포함하고 있다.

    • 괄호 안에 콤마로 나뉜 파라미터 리스트

      • 파라미터의 타입은 생략가능
      • 하나의 파라미터만 존재할 경우 괄호 생략 가능
    • 화살표 token, ->

    • 하나의 expression이거나 statement 블록을 담은 body

      • 하나의 expression을 정의하면 자바 런타임이 expression을 평가 후 value를 return 한다.

      • return statement로 대체할 수 있다.

      • return statement는 expression이 아니므로 {}사이의 statement를 닫아야한다.

      • void 메소드일 경우엔 닫지 않아도 된다.

      • // single expression
        p.getGender() == Person.Sex.MALE 
          && p.getAge() >= 18
          && p.getAge() <= 25

      // return statement
      p -> { return p.getGen == Person.Sex.MALE
      && p.getAge() >= 18
      && p.getAge() <= 25;
      }

                                

Accessing Local Variables of the Enclosing Scope

  • local, 익명 클래스와 같이 람다 표현식은 변수를 capture 할 수 있다.
  • enclosing scope의 지역 변수에 접근 가능
  • local, 익명 클래스와 다르게 shadowing 이슈가 존재하지 않는다.
  • 이말은 람다 표현식은 supertype으로부터 이름을 상속 받거나 새로운 level의 scope를 만들지 않는다.
  • 람다 표현식 안에서의 선언은 enclosing 환경에서 존재하는 것처럼 해석된다.

Target Typing

  • 람다 표현식의 type은 어떻게 결정될까?
  • 위의 예에서 람다 표현식은 CheckPerson tester 부분과 Predicate tester에서 사용됐다.
  • 자바 런타임이 printPerson 메소드를 호출했을때 CheckPerson 타입을 기대하므로 람다 표현식은 CheckPerson 타입이된다.
  • 자바 런타임이 printPersonWithPredicate를 호출했을때 Predicate을 기대해 람다 표현식은 Predicate 타입이 된다.
  • 이러한 메소드들이 기대하는 데이터 타입을 타겟 타입이라고 한다.
  • 자바 컴파일러는 람바 표현식이 발견된 곳의 context 또는 상황의 타겟 타입을 사용해 람다 표현식의 타입을 결정한다.
  • 즉 람다 표현식은 자바 컴파일러가 타겟 타입을 결정할 수 있는 상황에서 사용할 수 있다.
  • 상황 예
    • Variable declarations
    • Assignments
    • Return statements
    • Array initializers
    • Method or constructor arguments
    • Lambda expression bodies
    • Conditional expressions, ?:
    • Cast expressions

Method References

  • 익명 함수를 생성하기 위해 람다 표현식을 사용한다.
  • 그러나 가끔 람다 표현식은 이미 존재하는 함수를 부르는 역할만 한다.
  • 이러한 경우 그 존재하는 함수를 이름으로 호출하는 것이 더 확실하다.
  • 메소드 레퍼런스는 이러한 것을을 할 수 있게 해준다.
  • 이미 이름을 가진 함수를 위한 읽기 쉽고 컴팩트한 람다 표현식이다.
 Arrays.sort(rosterAsArray, new PersonAgeComparator());
 
sort 2번째 파라미터는 Comparator 함수형 인터페이스
함수형 인터페이스므로 Comparator를 구현한 클래스를 정의후 인스턴스를 생성하는 대신 람다 표현식을 사용할 수 있다.

Arrays.sort(rosterAsArray,
    (Person a, Person b) -> {
        return a.getBirthday().compareTo(b.getBirthday());
    }
);

만약 Person 클래스에 나이를 compare하는 함수가 이미 존재한다면 람다 표현식의 body 대신 사용할 수 있다.
  
Arrays.sort(rosterAsArray,
    (a, b) -> Person.compareByAge(a, b)
);
  
Because this lambda expression invokes an existing method, you can use a method reference instead of a lambda expression:
이 람다 표현식은 존재하는 함수를 호출하는 것이므로 람다표현식 대신 메소드 레퍼런스를 사용할 수 있다.
 
Arrays.sort(rosterAsArray,Person::compareByAge);
  
The method reference Person::compareByAge is semantically the same as the lambda expression (a, b) -> Person.compareByAge(a, b). Each has the following characteristics:

1. Its formal parameter list is copied from Comparator<Person>.compare, which is (Person, Person).
2. Its body calls the method Person.compareByAge.

Kinds of Method References

  • 4가지의 of method references:

  • Reference to a static method

    • ContainingClass::staticMethodName
  • Reference to an instance method of a particular object

    • containingObject::instanceMethodName
  • Reference to an instance method of an arbitrary object of a particular type

    • ContainingType::methodName
  • Reference to a constructor

    • ClassName::new

When to Use Nested Classes, Local Classes, Anonymous Classes, and Lambda Expressions

  • nested 클래스들은 한곳에서만 사용되는 클래스들을 논리적 그룹으로 묶고, 캡슐화를 증가시키며, 읽기 쉽고 유지가능한 코드를 만든다.

  • 각각의 클래스들은 이러한 공통된 장점과 특정 상황에 사용되도록 의도됐다.

  • Local class

    • 한번 이상 인스턴스를 만들 경우
    • 클래스의 생성자에 접근해야할 경우
    • 새로운 타입을 만들 경우
  • Anonymous class

    • 필드나 추가적인 메소들을 선언해야할 경우
  • Lambda expression

    • Use it if you are encapsulating a single unit of behavior that you want to pass to other code. For example, you would use a lambda expression if you want a certain action performed on each element of a collection, when a process is completed, or when a process encounters an error.

    • Use it if you need a simple instance of a functional interface and none of the preceding criteria apply (for example, you do not need a constructor, a named type, fields, or additional methods).

  • Nested class

    • Use it if your requirements are similar to those of a local class, you want to make the type more widely available, and you don't require access to local variables or method parameters.

    • Use a non-static nested class (or inner class) if you require access to an enclosing instance's non-public fields and methods. Use a static nested class if you don't require this access.

profile
안녕하세요

0개의 댓글