람다 표현식

2018, May 16    

#람다의 특징

  • 익명 : 보통의 메서드와 달리 이름이 없으므로 익명이라 표현한다.
  • 함수 : 메서드처럼 특정 클래스에 종속되지 않으므로 함수라 부른다.
  • 전달 : 람다 표현식을 메서드 인수로 전달하거나 변수로 저장할 수 있다.
  • 간결성 : 익명 클래스처럼 많은 자질구레한 코드를 구현할 필요가 없다.

람다lamda라는 용어는 람다 미적분학 학계에서 개발한 시스템에서 유래했다.
람다 표현식은 아래와 같이 세 부분으로 이루어 진다.

  • 파라미터 리스트 : 메서드의 파라미터
  • 화살표 : 화살표(->)는 람다의 파라미터 리스트와 바디를 구분한다.
  • 람다의 바디 : 두 사과의 무게를 비교한다. 람다의 반환값에 해당하는 표현식이다.
  •     () -> {}
        () -> 42
        () -> null
        () -> {return 42;}
        () -> { System.out.println("do something"); }
        () -> {
        if (true) { return 12;}
        else { return 11; }
        }
        (int x) -> x+1
        (x) -> x+1
        (Apple a) -> a.getWeight()
        


    #함수형 인터페이스

    람다식은 함수형 인터페이스를 표현하기 위해서 사용된다.

  • java8에서 동작(함수)를 파라미터화 하기 위해서 클래스의 선언과 인스턴스화를 동시에 수행할 수 있도록 익명 클래스라는 기법을 사용하였다.
  • 익명 클래스를 전달 할시 코드의 장황함을 해결하기 위해서 람다 표현식이 활용 된다.
  • 이런 익명 클래스의 추상화된 인터페이스를 함수형 인터페이스라고 하며,  함수형 인터페이스는 하나의 추상 메서드를 가지고 있다.
  • @FunctionalInterface :  java8에 도입된 어노테이션으로 함수형 인터페이스임을 가르키는 어노테이션이다. @FunctionalInterface로 인터페이서를 선언했지만 실제로 함수형 인터페이스가 아니면 컴파일러가 에러를 발생시킨다. 예를 들어 추상 메서드가 한 개 이상이라면 "Multiplenonoverriding abstract methods found in interface Foo(인터페이스 Foo에 오버라이드 하지 않은 여러 추상메서드가 있음)"같은 에러가 발생할 수 있다.

    자바8 API에는 java.util.faction 패키지안에 여러유형의 함수형 인터페이스를 제공하고 있다.
    api문서 참고 : Package java.util.function

    자바8의 대표적인 함수형 인터페이스

    </tr> </tr> </tr> </tr> </tr> </tbody> </table> </div> << 기본형 특화 >>
    자바의 모든 형식은 참조형(Byte, Integer, Object, List)과 기본형(int, double, byte, char)에 해당 한다. 하지만 함수형 인터페이스는 제네릭 파라미터를 씀으로 기본형의 데이터를 넘기더라도 참조형으로 변환해 버린다. (이런 동작을 오토박싱이라고 한다.)
        List
        <Integer> list = new ArrayList<>();
    
            for(int i = 300; i < 400; i++) {
            list.add(i); <-- int형을 자동으로 Integer로 박싱(boxing)
            }
            
    이런 변환 과정은 비용이 소모된다. 박싱한 값은 기본형을 감싸는 wrapper이며 Heap에 저장된다.
    따라서 박싱한 값은 메모리를 더 소비하며 기본형을 가져 올 때도 메모리를 탐색하는 과정이 필요하다.
    JVM 메모리 영역 (참조형 변수는 heap영역에, 기본형 변수는 stack에 저장된다.)

    java8에서는 이런 오토 박싱을 피할 수 있도록 기본형에 특화된 인터페이스를 제공한다.
    위 표에서 나열된 함수형 인테이스중 '기본형 특화'로 분류된 함수형 인터페이스들이 바로 이에 해당된다. (IntPredicate, LongPredicate 등)

    << 람다 캡처링capturing(포획) >>
    람다 표현식의 바디 부분도 익명 클래스와 마찬가지로 외부에서 정의된 변수(자유변수)를 활용 할 수 있다. 이와 같은 동작을 람다 캡쳐링(capturing lamda)라고 부른다.
    하지만 지역 변수를 사용하기 위해서는 명시적으로 final로 선언되어 있어야 하거나 실질적으로 final로 선언된 변수와 똑같이 사용되어야 한다.
            int portNumber = 1337;
            Runnable r = () -> System.out.println(portNumber);
            portNumber = 4443; // final로 변형되어 컴파일 오류가 발생
            
    이렇게 제약 변수에 제약을 두는 이유는 역시 지역변수가 저장되는 메모리 영역이 인스턴스 변수와 다르기 때문이다.
    인스턴스 변수는 힙에 저장되는 반면 지역 변수는 스택에 위치한다. 그래서 아래와 같은 케이스가 발생 할 수 있다.

    1. 외부에서 진행한 스레드에서 지역 변수를 한후
    -> 2. 람다에서 진행한 스레드에서 외부 변수를 사용
    -> 1번 쓰레드가 도중에 작업을 완료하면 지역 변수가 stack에서 해제됨.
    이때 2번 람다 스레드는 살아 있어 해당 변수에 접근하려고 시도함.

    이와 같은 이유 람다 바디에서는 실제 변수에 접근을 허용하는 것이 아닌 해당 변수의 복사본을 만들어 사용하는데, 처음에 복사한 값과 원본의 값이 달라지면 안되기 때문에, 람다에서 접근하는 지역 변수를 내부적으로 final로 선언한다.

    << 클로저 >>
    클로저란 클로저 외부에 정의된 변수의 값에 접근 할수 있는 내부 영역(? 함수)를 말한다.
    클로저는 3가지 scope를 가지고 있다.
    내부(블럭내에 정의된 변수)접근, 외부 함수의 변수에 대한 접근, 전역 변수에 대한 접근
    람다와 익명 클래스도 이런 클로저와 비슷한 동작을 수행한다. 다만 람다와 익명클래스는
    람다가 정의된 메서드의 지역 변수의 값을 바꿀 수 없다. 람다가 정의된 메서드의 지역변수값은 final 변수여야 한다. </div>
    함수형 인터페이스 함수 디스크립터 기본형 특화
    Predicate </td> T -> boolean IntPredicate, LongPredicate, DoublePredicate
    Consumer </td> T -> void IntConsumer, LongConsumer, DoubleConsumer
    Function <T , R> T -> R IntFunction , IntToDoubleFunction, IntToLongFunction, LongToDoubleFunction, DoubleFunction , LongToIntFunction, ... </td> </tr>
    Supplier </td> () -> T BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier
    UnaryOperator </td> T -> T IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator
    BinaryOperator </td> (T, T) -> T IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator
    BiPredicate <L ,R> (L, R) -> boolean
    BiConsumer <T , U> (T, U) -> void ObjIntConsumer , ObjLongConsumer , ObjDoubleConsumer </td> </tr>
    BiFunction <T , U, R> (T, U) -> R ToIntBiFunction <T ,U>, ToLongBiFunction <T , U>, ToDoubleBiFunction <T ,U>