람다 표현식은 하나의 메소드를 구현하는 인터페이스(함수형 인터페이스)의 간결한 문법을 위해 자바 8에 도입되었습니다.
함수형 인터페이스는 정확히 하나의 추상 메소드를 가진 인터페이스입니다. 예:
@FunctionalInterface interface MyAction { void perform(String s); }
람다 표현식은 해당 인터페이스를 구현할 수 있습니다:
MyAction action = (s) -> System.out.println(s); action.perform("Hello lambda!");
람다 표현식을 사용할 때 컴파일러는 어떤 인터페이스가 구현되는지 자동으로 이해합니다(타겟 타입 지정). 람다는 종종 컬렉션과 함께 사용됩니다:
List<String> list = Arrays.asList("one", "two", "three"); list.forEach(s -> System.out.println(s));
질문: 람다 표현식이 외부 클래스의 비정적 필드나 메소드를 참조할 수 있습니까? 이와 관련하여 어떤 제한이 있습니까?
답변: 람다 표현식은 외부 클래스의 필드와 메소드를 참조할 수 있지만, 외부 메소드의 로컬 변수를 사용하는 경우 해당 변수는 final 또는 effectively final (즉, 첫 번째 할당 이후 변경되지 않아야 함)이어야 합니다. 예:
void doIt() { int x = 42; Runnable r = () -> System.out.println(x); // x는 effectively final이어야 함 }
x를 선언 후 변경하면 컴파일 오류가 발생합니다.
이야기
메소드 내에서 람다를 사용할 때 외부 로컬 변수를 변경하려고 시도하여 "람다 표현식에서 사용되는 변수는 final 또는 effectively final이어야 합니다"라는 컴파일 오류가 발생했습니다. 개발팀은 원인을 찾기 위해 많은 시간을 보냈고 이 제한을 기억할 때까지였습니다.
이야기
한 프로젝트에서 사용자 정의 인터페이스를 람다에 사용했지만
@FunctionalInterface로 주석을 다는 것을 잊었습니다. 리팩토링 후 인터페이스에 두 번째 메소드를 추가하여 프로젝트가 컴파일되지 않았습니다. 이는 예기치 않은 오류를 초래했고 이를 찾기가 어려웠습니다.
이야기
람다 표현식을 포함한 객체를 직렬화하려고 시도한 결과 직렬화/역직렬화가 올바르게 작동하지 않았습니다 - 람다는 기본적으로 직렬화되지 않습니다. 람다에 불일치하는 의존성이 포함되어 있다면 네트워크를 통해 전달할 때 오류가 발생할 수 있음을 기억하는 것이 중요합니다.