익명클래스 vs 람다식 비교
- Coding/Java
- 2022. 1. 25.
람다표현식
메서드를 하나의 식(expression)으로 표현한 것이다. 메서드를 람다식으로 표현하면 메서드 이름과 반환값이 존재하지 않기 때문에 이를 '익명함수' 라고도 한다.
람다표현식의 뜻을 글로만 보면 감이 안올 수 있다. 아래 예제로 어떤식으로 람다표현식이 사용되는지 눈으로 확인하자.
람다식 예제
import dto.SampleDto;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Basic {
private void test() {
List<SampleDto> sampleDtoList = new ArrayList<>();
// 람다식 사용
sampleDtoList.sort(
(SampleDto sampleDto1, SampleDto sampleDto2) -> sampleDto1.getName().compareTo(sampleDto2.getName())
);
}
}
람다표현식이 필요한 이유
우선 아래 예제를 보자. 위의 '람다식 예제'의 코드는 기존에 익명클래스로도 구현이 가능하다. 익명클래스와 람다표현식의 차이를 눈여겨보자.
import dto.SampleDto;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Basic {
private void test() {
List<SampleDto> sampleDtoList = new ArrayList<>();
// 익명클래스 사용
sampleDtoList.sort(new Comparator<SampleDto>() {
@Override
public int compare(SampleDto sampleDto1, SampleDto sampleDto2) {
return sampleDto1.getName().compareTo(sampleDto2.getName());
}
});
// 람다식 사용
sampleDtoList.sort(
(SampleDto sampleDto1, SampleDto sampleDto2) -> sampleDto1.getName().compareTo(sampleDto2.getName())
);
}
}
위 익명 클래스 사용 로직부터 분석해보자.
...
sampleDtoList.sort(new Comparator<SampleDto>() {
@Override
public int compare(SampleDto sampleDto1, SampleDto sampleDto2) {
return sampleDto1.getName().compareTo(sampleDto2.getName());
}
});
...
우선 List.java 의 sort() 를 호출하였다. sort() 메서드는 다음과 같다.
...
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
...
인자로 Comparator 인터페이스를 받는다. 이 뜻은 Comparator 인터페이스를 구현한 객체를 받는다는 의미다. 익명클래스는 Comparator 인터페이스를 구현한 클래스를 가지지않고도 로직 안에서 객체를 생성하여 파라미터로 넘길 수 있다.
- 익명클래스
...
sampleDtoList.sort(new Comparator<SampleDto>() {
@Override
public int compare(SampleDto sampleDto1, SampleDto sampleDto2) {
return sampleDto1.getName().compareTo(sampleDto2.getName());
}
});
...
위 코드를 람다표현식으로 표현하면 아래와 같다. 기능은 익명클래스와 모두 동일하다.
- 람다표현식
// 람다식 사용
sampleDtoList.sort(
(SampleDto sampleDto1, SampleDto sampleDto2) -> sampleDto1.getName().compareTo(sampleDto2.getName())
);
위 람다표현식은 아래의 장점을 가진다.
1) 이름 없는 함수 선언 가능
2) 소스코드의 분량을 줄일 수 있고, 반복 코드 관리에 유용하다.
3) 코드를 파라미터로 전달이 가능하여, 동작을 정의하여 메서드에 전달할때 편리하게 사용이 가능하다.
함수형 인터페이스 (@FunctionalInterface)
위 예제 코드를 따라오면서 한가지 의문점이 들 수 있다. 람다표현식은 메서드 명도 없고, 단순히 구현 로직을 명시한다. 그렇다면 만약 여러개의 추상메서드가 있는 인터페이스의 경우에는 어떻게 처리될까?
정답을 말하자면, 위 상황에서 람다표현식의 사용은 불가능하다. 람다표현식은 함수형 인터페이스의 경우에만 가능하다. 위에서 예제로 설명했던 Comparator 인터페이스를 보자.
Comparator.java
package java.util;
import java.io.Serializable;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.ToDoubleFunction;
import java.util.Comparators;
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
// Object의 public 함수이므로 추상 메서드로 속하지 않는다.
// boolean equals(Object obj);
...
}
우선 다른 default 메서드는 제외하고 추상 메서드만 가져왔다. compare 메서드 단 1개만을 갖고있다. 즉, 함수형 인터페이스란 하나의 추상메서드만을 갖고있는 인터페이스로, 이러한 함수형 인터페이스의 경우에만 람다표현식 사용이 가능하다.
어노테이션
@FunctionalInterface
함수형 인터페이스라는 의미를 어노테이션으로 명시 가능하다. 생략이 가능하지만, 명시적으로 사용해주는 것을 권장한다. 이유는 해당 어노테이션의 선언으로 혹시라도 인터페이스에 추상 메서드가 2개 이상으로 선언되면 컴파일 에러가 발생하여 오류를 방지할 수 있기 때문이다.
Object 의 public 메서드
위 Comparator 인터페이스에서 아래 코드를 짚고 넘어가보자.
- 함수형 인터페이스인 경우
int compare(T o1, T o2);
// Object의 public 함수이므로 추상 메서드로 속하지 않는다.
boolean equals(Object obj);
Comparator 인터페이스에 추상 메서드는 compare, equals 총 2개였는데 함수형 인터페이스가 가능했다. 이유는 equals 메서드는 Object 객체의 public 메서드이기 때문에 포함되지 않았기 때문이다.
- 함수형 인터페이스가 아닌 경우
int compare(T o1, T o2);
// Object의 public 메서드가 아니므로 추상메서드로 포함된다.
Object clone();
만약 위의 clone 메서드가 선언되어 있었다면 그것은 함수형 인터페이스가 될 수 없었을 것이다. Object 클래스의 public 메서드일 경우에만 추상메서드 개수로 포함되지 않는 것이다.
위 내용 참고 : http://wiki.sys4u.co.kr/pages/viewpage.action?pageId=7766426#app-switcher
'Coding > Java' 카테고리의 다른 글
[JAVA8 병렬프로그래밍] 컨커런트 API (0) | 2022.06.14 |
---|---|
[Java] Stream 사용하여 String 이 null이 아닐 경우 concat(joining) 수행하기 (0) | 2022.03.23 |
JVM GC (Garbage Collection) 에 대한 정리 (2) | 2022.01.16 |
[Stream] String 에서 숫자를 추출하여 총 합(sum) 구하기 (0) | 2021.12.23 |
[Stream] String에서 숫자가 아닌 값을 추출하여 String으로 변환하기 (0) | 2021.12.23 |