Java Method Reference(::) 완벽 이해하기
Java Stream과 Lambda를 공부하다 보면 정말 자주 보게 되는 문법이 바로:
::
입니다.
대표적으로:
System.out::println
같은 코드.
처음 보면:
“이거 왜 쓰는 거지?”
싶기 쉽습니다.
하지만 Method Reference는 단순 축약 문법이 아니라:
- Lambda
- 함수형 인터페이스
- Stream API
- JVM method handle
- 생성자 참조(Constructor Reference)
까지 연결되는 중요한 기능입니다.
이번 글에서는:
- Method Reference란?
- 람다와 차이
- 종류 4가지
- static/instance reference
- 생성자 참조
- 실무 사용 패턴
- JVM 내부 동작
까지 깊게 정리해보겠습니다.
1. Method Reference란?
Method reference 는:
기존 메서드를 람다처럼 전달하는 문법
입니다.
2. 가장 기본 예시
x -> System.out.println(x)
↓
System.out::println
축약 가능.
3. 왜 등장했을까?
람다도 간단하지만:
x -> someMethod(x)
처럼:
“전달만 하는 람다”
가 너무 많았기 때문.
4. 핵심 아이디어
즉:
“메서드 자체를 값처럼 전달”
하는 것.
5. Method Reference는 언제 가능할까?
매우 중요.
다음 형태일 때만 가능.
기존 람다
x -> method(x)
Method Reference
ClassName::method
즉:
단순 전달 형태
일 때 가능.
6. 대표 예시
list.forEach(System.out::println);
7. 실제 타입은?
여기서:
System.out::println
은 실제로:
Consumer<T>
구현체.
8. 람다와 동일한 의미
즉:
x -> System.out.println(x)
와 동일.
9. Method Reference 종류
매우 중요.
총 4가지 대표 형태 존재.
10. ① Static Method Reference
형태:
ClassName::staticMethod
11. 예시
Integer::parseInt
12. 람다로 풀면
s -> Integer.parseInt(s)
13. Stream 예시
list.stream()
.map(Integer::parseInt)
14. ② 특정 객체의 Instance Method Reference
형태:
object::instanceMethod
15. 예시
PrintStream out = System.out;
Consumer<String> c =
out::println;
16. 람다로 풀면
s -> out.println(s)
17. ③ 임의 객체의 Instance Method Reference
가장 헷갈리는 유형.
18. 형태
ClassName::instanceMethod
19. 예시
String::toUpperCase
20. 람다로 풀면
s -> s.toUpperCase()
21. 왜 가능할까?
첫 번째 파라미터가:
메서드 호출 대상 객체
로 사용되기 때문.
22. 매우 중요한 예시
list.stream()
.map(String::length)
23. 실제 의미
s -> s.length()
24. ④ Constructor Reference
매우 중요.
25. 형태
ClassName::new
26. 예시
Supplier<User> s =
User::new;
27. 람다로 풀면
() -> new User()
28. 생성자 파라미터도 가능
Function<String, User> f =
User::new;
29. 의미
name -> new User(name)
30. 배열 생성도 가능
IntFunction<int[]> f =
int[]::new;
31. Method Reference와 함수형 인터페이스
매우 중요.
Method Reference는 반드시:
함수형 인터페이스 문맥
필요.
32. 예시
Function<String, Integer> f =
Integer::parseInt;
컴파일러가:
어떤 메서드와 매핑할지 추론
합니다.
33. Method Overloading 주의
매우 중요.
예:
println(...)
오버로딩 매우 많음.
34. 그런데 왜 동작할까?
컴파일러가:
함수형 인터페이스 시그니처
기반으로 적절한 메서드 선택.
35. JVM 내부 동작
람다와 동일하게 대부분:
invokedynamic
기반 처리.
36. Method Handle 사용
Method handle 기반으로:
메서드 참조 연결
수행.
37. 왜 중요한가?
JVM이:
- lazy linking
- 최적화
- inline
하기 더 유리.
38. 람다 vs Method Reference
| 항목 | 람다 | Method Reference |
| 표현력 | 자유로움 | 단순 전달 특화 |
| 가독성 | 상황 따라 다름 | 간결 |
| 복잡 로직 | 가능 | 불가능 |
39. Method Reference가 항상 좋은 건 아니다
매우 중요.
40. 안 좋은 예
.map(UserService::convertAndValidateAndNormalize)
너무 길고 의미 불명확 가능.
41. 오히려 람다가 더 나을 수도
.map(user -> normalize(user))
더 읽기 쉬운 경우 많음.
42. Stream API에서 매우 많이 사용
대표:
.map(User::getName)
.filter(String::isBlank)
.forEach(System.out::println)
43. Comparator와도 연결
Comparator.comparing(User::getAge)
44. Optional과도 연결
optional.ifPresent(System.out::println)
45. 실무에서 자주 하는 실수
1) Method Reference 남용
오히려 가독성 저하 가능.
2) 임의 객체 instance reference 이해 부족
String::length
헷갈리기 쉬움.
3) 오버로딩 충돌
컴파일러 추론 실패 가능.
4) 람다와 Method Reference 차이 오해
Method Reference는 “단순 전달” 전용.
46. 핵심 흐름 요약
람다 표현식
↓
단순 메서드 호출 형태
↓
Method Reference(::)로 축약 가능
47. 종류 정리
| 종류 | 예시 |
| static method | Integer::parseInt |
| 특정 객체 method | out::println |
| 임의 객체 method | String::length |
| constructor | User::new |
48. 가장 중요한 핵심 한 줄
Method Reference는
“기존 메서드를 함수형 인터페이스 구현처럼 전달하는 문법”
입니다.
49. 정리
Method Reference는 단순 축약 문법이 아닙니다.
실제로는:
- Lambda
- 함수형 인터페이스
- Stream API
- Constructor Reference
- JVM invokedynamic
전체와 연결되는 Java 함수형 프로그래밍 핵심 기능입니다.
특히 실무에서는:
- Stream map/filter
- Comparator.comparing
- 생성자 참조
- 오버로딩 추론
- 가독성 기준
을 정확히 이해하는 것이 매우 중요합니다.
다음 글에서는:
Collector 활용
을 Collectors.toList(), groupingBy(), partitioningBy(), downstream collector, 병렬 수집 구조까지 포함해서 깊게 정리해보겠습니다.
'language > java' 카테고리의 다른 글
| Java Optional<T> 사용법 완벽 이해하기 (0) | 2026.05.28 |
|---|---|
| Java Collector 활용 완벽 이해하기 (0) | 2026.05.28 |
| Java Stream API 기초 완벽 이해하기 (0) | 2026.05.27 |
| Java 함수형 인터페이스(Function, Predicate, Consumer 등) 완벽 이해하기 (0) | 2026.05.27 |
| Java 익명 클래스 vs 람다 완벽 이해하기 (1) | 2026.05.27 |
댓글