람다(Lambda expression)
람다는 자바에 함수형 프로그래밍을 가능하게 하면서 간결하고 표현력이 풍부해지며 가독성이 높아지는 등 많은 이점을 가져와 줬다고 생각합니다. 그렇다면 이 람다는 무엇이고, 어떻게 작성되는 것인지 Java API를 참고하면서 설명해보겠습니다.
What is Lambda?
람다식은 Java 8부터 도입 되었고, 메서드를 하나의 식 형태로 나타낼 수 있게 해주는 기능입니다.
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
위의 람다식 활용은 우선순위큐의 정렬 기준을 식의 형태로 간단하게 지정해 줄 수 있음을 알게 해줍니다.
람다식이 없었다면 코드를 좀 더 작성하고 살짝 비효율적이라고 느껴지는 방식을 사용해야 하는데
PriorityQueue<int[]> p = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
}
});
이런 식으로 작성을 해야 됩니다. 두 코드 명령줄을 비교했을 때 람다식을 이용한 코드가 확실히 더 보기 좋고 의도가 명확해 보입니다.
람다식을 사용하지 않은 경우를 보시면 저건 익명 객체를 하나 만들어 인터페이스를 구현하도록 작성한 코드입니다.
PriorityQueue의 생성자 중에 이렇게 Comparator를 매개변수로 받는 생성자가 있는데 이 Comparator 객체를 하나 만들어 compare 함수를 구현한 것입니다.
결국 람다식은 클래스 혹은 인터페이스의 타입(Comparator<int[]>)을 저장할 참조 변수 하나(생성자) 그리고 해당 타입에 람다식과 동일한 메서드(compare(T o1,T o2))가 정의되어 있어야 합니다.
이 개념을 알고 있어야 람다식의 정체와 간략하게 생략해도 의도를 명확하게 알 수 있습니다.
이렇듯 하나의 메서드를 선언한 인터페이스의 경우 람다식으로 다루는 것이 기존 Java의 규칙을 어기지 않으면서 자연스러운 형태가 되었습니다.
그래서 람다식은 인터페이스를 통해 다루기로 하였으며, 람다식을 다루기 위한 인터페이스를 '함수형 인터페이스(functional interface)' 라고 부르기로 했습니다.
Comparator 인터페이스에도 단 하나의 추상 메서드만 정의되어 있고, 나머지 함수들은 default 나 static 입니다. 자세한 건 IDE나 인터넷 검색을 통해 Java API 문서를 살펴보시면 될 거 같습니다.
How To Write a Lambda expression
람다식 작성 방식은
1. 반환 타입을 제거하고 '->' 를 블록 앞에 추가
//1 적용 전
PriorityQueue<int[]> p = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
}
});
-----------------------------------------------------------------------------------
//1 적용 후
PriorityQueue<int[]> p = new PriorityQueue<>(new Comparator<int[]>() {
@Override
(int[] o1, int[] o2) -> {
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
}
});
2. 반환값이 있는 경우, 식이나 값만 적고 return문을 생략(끝에 ';' 안 붙임)
//2 적용 전
PriorityQueue<int[]> p = new PriorityQueue<>(new Comparator<int[]>() {
@Override
(int[] o1, int[] o2) -> {
return o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0];
}
});
-----------------------------------------------------------------------------------
//2 적용 후
PriorityQueue<int[]> p = new PriorityQueue<>((int[] o1, int[] o2) -> o1[0] == o2[0] ? o1[1] - o2[1] : o1[0] - o2[0]);
여기까지만 해도 되겠지만 Java 람다식은 매개변수 타입이 추론 가능한 경우라면 생략이 가능하고
대부분의 경우 생략 가능합니다.
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
그러면 이제 맨 처음에 보여드렸던 코드와 똑같아 집니다.
이외에도 작성 규칙이 몇 개 더 있는데
1. 매개변수가 하나인 경우 ()를 생략해 줄 수 있습니다.
(a) -> ... == a -> ...
2. 블록 안의 문장이 하나뿐 일 때, 괄호 {} 생략 가능(끝에 ';' 안 붙임)
a -> { System.out.println(a) } == a -> Sytem.out.println(a)
이렇게 람다식이 무엇이고 Java API 의 PriorityQueue 와 Comparator 를 살펴보면서 알아보았고, 어떻게 작성되는지 작성 방식을 하나씩 적용하면서 살펴보았습니다.
프로그래밍에서 프로그래머에게 코드 작성과 가동성 면에서 큰 도움을 주는 람다식을 개발해주신 선임 Java 개발자분들에게 감사를 표하며 글을 마치겠습니다.
'Programming Language > Java' 카테고리의 다른 글
Java Start (0) | 2024.06.18 |
---|---|
JVM Execution - 자바 코드가 기계어로 번역되기까지 (2) | 2023.08.27 |
Java reflection API (0) | 2023.08.19 |
Java의 동작 방식에 대하여 - JVM Architecture, ClassLoader (0) | 2023.07.19 |