Java 익명 클래스 vs 람다 완벽 이해하기
Java 8 이후 람다(Lambda)가 등장하면서 많은 개발자가:
익명 클래스는 이제 안 쓰는 거 아냐?
라고 생각하기 쉽습니다.
하지만 실제 실무에서는:
- 익명 클래스
- 람다
- 내부 클래스
- 함수형 인터페이스
를 정확히 구분해야 합니다.
특히:
- this 동작 차이
- 변수 capture 방식
- JVM 내부 생성 구조
- bytecode 차이
- 메모리 구조
까지 이해해야 진짜 Java 동작 원리를 이해할 수 있습니다.
이번 글에서는:
- 익명 클래스란?
- 람다와의 차이
- this 차이
- capture 차이
- bytecode/JVM 차이
- 언제 무엇을 써야 하는가
까지 깊게 정리해보겠습니다.
1. 익명 클래스란?
Anonymous inner class 는:
이름 없는 내부 클래스
입니다.
2. 기본 예시
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("run");
}
};
3. 왜 만들었을까?
목표:
“한 번만 사용할 클래스”
간단하게 만들기 위해.
4. Java 8 이전 문제
대표 문제:
코드 너무 장황함
특히:
- 이벤트 처리
- Comparator
- Runnable
같은 작은 동작 구현에도 클래스 전체 작성 필요.
5. 그래서 등장한 람다
동일 코드를 람다로:
Runnable r =
() -> System.out.println("run");
6. 훨씬 간단해짐
즉 람다 핵심 목적은:
불필요한 문법 제거
입니다.
7. 그런데 중요한 오해
매우 중요합니다.
람다는:
익명 클래스와 완전히 같지 않음
입니다.
8. 핵심 차이 1: this
가장 중요.
9. 익명 클래스의 this
예:
new Runnable() {
@Override
public void run() {
System.out.println(this);
}
}
여기서:
this
=
익명 클래스 객체 자신
입니다.
10. 람다의 this
Runnable r = () -> {
System.out.println(this);
};
여기서:
this
=
바깥 클래스 객체
입니다.
11. 왜 다를까?
매우 중요.
람다는:
“새로운 클래스 scope”
를 만들지 않기 때문.
12. 즉 람다는 진짜 클래스가 아니다
핵심.
익명 클래스:
새로운 객체 생성
람다:
함수형 인터페이스 구현 표현
에 가까움.
13. 변수 shadowing 차이
예:
int x = 10;
14. 익명 클래스에서는 가능
new Runnable() {
int x = 20;
}
가능.
왜냐하면:
새로운 scope 생성
하기 때문.
15. 람다에서는 불가능
int x = 20;
동일 변수명 선언 불가.
왜냐하면:
바깥 scope 공유
하기 때문.
16. 핵심 차이 2: 클래스 생성 여부
익명 클래스는 실제로:
별도 .class 파일 생성
가능.
17. 예시
컴파일 시:
Outer$1.class
같은 파일 생성 가능.
18. 람다는 다름
람다는 일반적으로:
invokedynamic
기반 처리.
19. invokedynamic란?
InvokeDynamic 는:
JVM이 런타임에 동적으로 연결하는 bytecode 명령
입니다.
20. 왜 중요할까?
JVM이:
- 최적화
- lazy 생성
- 메모리 절약
하기 더 유리.
21. 익명 클래스의 문제
익명 클래스는:
클래스 메타데이터 생성 비용
존재.
22. 람다는 더 가볍다
보통 JVM이:
더 효율적으로 처리 가능
합니다.
23. 핵심 차이 3: capture 방식
둘 다 외부 변수 사용 가능.
24. 예시
int number = 10;
25. 익명 클래스
new Runnable() {
@Override
public void run() {
System.out.println(number);
}
}
26. 람다
() -> System.out.println(number)
27. 둘 다 제약 존재
매우 중요.
effectively final
이어야 함.
28. 왜 제한할까?
지역 변수는:
Stack 메모리
에 존재.
하지만 람다/익명 클래스는:
나중에 실행 가능
합니다.
즉:
생명주기 차이 문제
발생 가능.
29. 그래서 capture 수행
실제로는:
값 복사(capture)
수행.
30. 핵심 차이 4: 함수형 인터페이스 제한
람다는 반드시:
함수형 인터페이스
필요.
31. 익명 클래스는 제한 없음
아무 인터페이스/클래스 구현 가능.
32. 예시
new Thread() {
}
가능.
33. 람다는 불가능
추상 메서드 여러 개면:
컴파일 불가
34. bytecode 관점 차이
익명 클래스:
실제 클래스 생성
35. 람다:
LambdaMetafactory
+
invokedynamic
활용.
36. 그래서 람다가 더 현대적
특히:
- Stream API
- CompletableFuture
- 함수형 스타일
과 궁합 좋음.
37. 그런데 익명 클래스가 완전히 사라졌을까?
아님.
38. 익명 클래스가 더 적합한 경우
대표:
- 상태(state) 보유
- 메서드 여러 개
- 추가 필드 필요
- this 독립 필요
39. 예시
new MouseAdapter() {
@Override
public void mouseClicked(...) {
}
@Override
public void mousePressed(...) {
}
}
람다 불가능.
40. 람다가 적합한 경우
대표:
- 짧은 동작
- 함수형 처리
- Stream
- Comparator
41. Comparator 예시
예전:
new Comparator<User>() {
@Override
public int compare(...) {
}
}
현대:
(a, b) -> a.getAge() - b.getAge()
42. 성능 차이 있을까?
대부분 경우:
람다가 더 유리하거나 비슷
합니다.
하지만 보통:
가독성이 더 중요
한 경우 많음.
43. 실무에서 자주 하는 실수
1) 람다에서 this 오해
매우 흔함.
2) 람다 안에 복잡 로직 작성
가독성 저하.
3) effectively final 이해 부족
컴파일 오류 발생.
4) 익명 클래스와 람다를 완전히 동일하게 생각
내부 동작 다름.
44. 핵심 비교 정리
| 항목 | 익명 클래스 | 람다 |
| 클래스 생성 | O | X(동적 처리) |
| this | 자기 자신 | 바깥 객체 |
| 새로운 scope | O | X |
| 함수형 인터페이스 필요 | X | O |
| 문법 | 장황 | 간결 |
45. 핵심 흐름 요약
익명 클래스
=
실제 내부 클래스 객체
람다
=
함수형 인터페이스 구현 표현식
46. 가장 중요한 핵심 한 줄
람다는 익명 클래스를 “짧게 쓴 것”처럼 보이지만,
실제로는 JVM 동작 방식까지 다르다
입니다.
47. 정리
익명 클래스 vs 람다는 단순 문법 차이가 아닙니다.
실제로는:
- JVM bytecode
- invokedynamic
- this binding
- scope
- closure/capture
전체와 연결되는 Java 내부 동작 핵심 개념입니다.
특히 실무에서는:
- this 차이
- 함수형 인터페이스 제한
- effectively final
- 람다 가독성
- 익명 클래스 사용 시점
을 정확히 이해하는 것이 매우 중요합니다.
다음 글에서는:
함수형 인터페이스(Function, Predicate, Consumer 등)
를 Java 기본 Functional Interface 설계 철학, Stream 연결, 실무 사용 패턴까지 포함해서 깊게 정리해보겠습니다.
'language > java' 카테고리의 다른 글
| Java Stream API 기초 완벽 이해하기 (0) | 2026.05.27 |
|---|---|
| Java 함수형 인터페이스(Function, Predicate, Consumer 등) 완벽 이해하기 (0) | 2026.05.27 |
| Java 람다 표현식(Lambda) 완벽 이해하기 (0) | 2026.05.27 |
| Java ConcurrentHashMap 기초 완벽 이해하기 (0) | 2026.05.27 |
| Java Immutable Collection 만들기 완벽 이해하기 (0) | 2026.05.27 |
댓글