람다 표현식
람다 표현식(lambda expression)이란 함수형 프로그래밍을 구성하기 위한 함수식이며, 간단히 말해 자바의 메소드를 간결한 함수식으로 표현한 것이다.
지금까지 자바에서는 메서드를 하나 표현하려면 클래스를 정의해야 했다. 하지만 람다식으로 표현하면 메서드의 이름과 반환값을 생략할 수 있고 이를 변수에 넣어 자바 코드가 매우 간결해지는 장점이 있다.
아래 그림에서 보듯이 int add(int a, int b) {} 메소드 표현식을, 메서드 타입, 메서드 이름, 매개변수 타입, 중괄호, return 문을 생략하고, 화살표 기호를 넣음으로써 코드를 혁명적으로 함축했음을 볼 수 있다. 이러한 특징으로 람다식을 이름이 없는 함수 익명 함수(anonymous function) 라고도 한다.
사실 람다식도 결국은 객체이다. 정확히 말하면 인터페이스를 익명 클래스로 구현한 익명 구현 객체를 짧게 표현한 것 뿐이다.
아무 클래스나 추상 클래스의 메소드를 람다식으로 줄이거나 하는 행위는 못한다라는 뜻이다. 오로지 인터페이스로 선언한 익명 구현 객체만이 람다식으로 표현이 가능하다. 그리고 람다 표현이 가능한 이러한 인터페이스를 가리켜 함수형 인터페이스라 총칭한다.
함수형 인터페이스
함수형 인터페이스란 딱 하나의 추상 메소드가 선언된 인터페이스를 말한다. 위의 IAdd 인터페이스 예제 코드가 바로 함수형 인터페이스 이다. 그리고 람다식은 함수형 인터페이스 안에 정의된 하나의 추상 메소드 선언을 짧게 표현한 것이다.
생각해보면 람다식 자체가 하나의 메소드를 한줄로 정의하는 표현식이기 때문에, 인터페이스에 두개 이상 추상 메서드가 들어있으면 이를 코드로 겹쳐 표현할 방법이 달리 없기 때문에, 오로지 추상 메소드 한개만 가진 인터페이스가 람다식의 타겟 타입(targe type)이 될 수 있는 것이다.
단, Java 8 버전 부터 이용이 가능한 인터페이스의 final 상수나 default, static, private 메서드는 추상 메서드가 아니기 때문에, 이들 여러개가 인터페이스에 들어있어도 오로지 추상 메서드가 한개이면 함수형 인터페이스로 취급 된다.
나만의 함수적 인터페이스를 만들 때 두 개 이상의 추상 메소드가 선언되지 않도록 컴파일러가 checking 해주는 기능이 있는데, 인터페이스 선언 시 @FunctionalInterface 어노테이션을 붙여주게 된다면 두 개 이상의 메소드 선언 시 컴파일 오류를 발생시켜준다. 이는 개발자의 실수를 줄여주는 역할을 한다.
람다식의 타입 추론
람다식으로 코드를 혁신적으로 줄일 수 있다는 점은 알았다. 그런데 리턴 타입도 파라미터 타입도 없는 람다식을 컴파일러가 이 함수가 어떤 타입 함수인지 알고 문법을 허용하는 것일까?
사실 컴파일러 스스로 람다 함수식을 보고 추론하여 타입을 유추하기 때문에 가능한 것이다. 무슨 AI 처럼 추론할 정도는 아니고 사람이 미리 정의해놓은 정의문을 보고 추론해주는 것이다.
람다 표현식의 한계
1. 람다는 문서화를 할 수 없다.
람다 자체는 이름이 없는 함수이기 때문에 메서드나 클래스와 다르게 문서화를 할 수 없다. 그래서 코드 자체로 동작이 명확하게 설명되지 않거나 람다가 길거나 읽기 어렵다면, 쓰지 않는 방향으로 리팩토링하는 것을 고려해야 한다.
2. 람다는 디버깅이 다소 까다롭다
람다식은 기본적으로 익명 구현 객체 기반이기 때문에, 익명 객체 특성상 디버깅 할때 콜 스택(call stack) 추적이 매우 어려운 단점을 가지고 있다.
이는 람다가 내부적으로 수행하는 작업이 더 많기 때문에 발생하는 현상이기 때문에, 코드가 복잡해질록 어디에서 문제가 발생했는지 확인하기가 어려워지게 된다. 그리고 이는 곧 성능과 연결 되기도 한다.
3. stream에서 람다를 사용할 시 for문 보다 성능이 떨어진다
어플리케이션 성능에 매우 민감한 사람이라면 치명적인 단점이 될 수도 있다.
4. 람다를 남발하면 코드가 지저분해질 수 있다
기존에는 동작 행위를 미리 클래스의 메서드로 정의해놓고 실행부에서 갖다 쓰는 것이었지만, 람다는 동작 행위를 실행부에서 지정하는 식이다. 그래서인지 람다식을 남발하다보면 비슷하게 생긴 함수를 계속 중복 생성하고 있는 자신을 발견 할 수 있다.
5. 재귀로 만들경우에는 다소 부적합하다
람다식을 통해 재귀 함수를 구축하면 실행 조차 안되는 컴파일 에러가 나타난다.