이전의 자바
예전에는 자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스(드물게는 추상 클래스)를 사용했다.
이런 인터페이스의 인스턴스를 함수객체(function object)라고 하여, 특정 함수나 동작을 나타내는 데 썼다.
Collections.sort(words, new Comparator<String>(){
public int compare(String s1, String s2){
return Integer.compare(s1.length(), s2.length());
}
}
});
이 코드에서 Comparator 인터페이스가 정렬을 담당하는 추상 전략을 뜻하며, 문자열을 정렬하는 구체적인 전략을 익명 클래스로 구현하였다. 하지만 익명 클래스 방식은 코드가 너무 길기 때문에 자바는 함수형 프로그래밍에 적합하지 않았다.
람다의 등장 - 자바 8 이후
자바 8에 와서 추상 메서드 하나짜리 인터페이스는 특별한 의미를 인정받아 특별한 대우를 받게 되었다. 지금은 함수형 인터페이스라 불리는 이 인터페이스들의 인스턴스를 람다식(lambda expression)을 사용해 만들 수 있게 된 것이다.
Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
여기서 람다, 매개변수(s1,s2), 반환값의 타입은 각각 Comparator
- 타입을 명시해야 코드가 더 명확할 때만 제외하고는, 람다의 모든 매개변수 타입은 생략하자.
람다 자리에 비교자 생성 메서드를 사용하면 이 코드를 더 간결하게 만들 수 있다.
Collections.sort(words, comparingInt(String::length));
더 나아가 자바 8, List 인터페이스에 추가된 sort 메서드를 이용하면 더욱 짧아진다.
words.sort(comparingInt(String::length));
열거 타입을 람다로
public enum Operation{
PLUS("+"){
public double apply(double x, double y){ return x + y; }
},
MINUS("-"){
public double apply(double x, double y){ return x - y; }
},
...
열거 타입에 인스턴스 필드를 두는 방식에서 람다를 이용하면 상수별로 다르게 동작하는 코드를 쉽게 구현할 수 있다.
public enum Operation{
PLUS("+", (x,y) -> x+y ),
MINUS("-", (x,y) -> x+y ),
...
람다의 단점
- 람다는 이름이 없고 문서화도 못한다.
- 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야 한다.
람다의 한계
람다의 시대가 열리면서 익명 클래스는 설 자리가 크게 좁아진 게 사실이다. 하지만 람다로 대체할 수 없는 곳이 있다.
- 람다는 함수형 인터페이스에서만 쓰인다. 예컨대 추상 클래스의 인스턴스를 만들 때 람다를 쓸 수 없으니, 익명 클래스를 써야 한다.
- 비슷하게 추상 메서드가 여러 개인 인터페이스의 인스턴스를 만들 때도 익명 클래스를 쓸 수 있다.
- 마지막으로 람다는 자신을 참조할 수 없다. 람다에서 this 키워드는 바깥 인스턴스를 가리킨다. 반면 익명 클래스에서의 this는 익명 클래스의 인스턴스 자신을 가리킨다.
- 람다도 익명 클래스처럼 직렬화 형태가 구현별로 다를 수 있다. 따라서 람다를 직렬화하는 일은 극히 삼가야 한다.
'Java' 카테고리의 다른 글
Garbage Collector (정의와 종류) (0) | 2022.06.06 |
---|---|
Java String이란? (StringBuilder, StringBuffer, String Iterning, String pool) (0) | 2022.06.04 |
JVM (Java Virtual Machine)과 메모리 영역 (0) | 2022.06.02 |
Java 8, 9, 10, 11 무슨 일이 일어나고 있는가? (0) | 2020.09.21 |
Exception (0) | 2020.07.15 |