[Java] "코드를 변수에 담다" - 람다식(Lambda) 완벽 가이드
자바 8 이전의 자바는 철저하게 객체지향 중심이었습니다. 메서드 하나를 전달하려고 해도 반드시 클래스를 만들고 객체를 생성해야 했죠. 하지만 람다식의 등장으로 자바에서도 '함수형 프로그래밍'이 가능해졌습니다. 오늘은 스트림(Stream)의 근간이자 코드의 가독성을 극적으로 높여주는 람다식에 대해 깊이 있게 알아보겠습니다.
1. 람다식(Lambda Expression)이란?
람다식은 이름이 없는 함수, 즉 익명 함수(Anonymous Function)를 지칭하는 용어입니다. 메서드를 하나의 '식(Expression)'으로 표현하여, 메서드의 인자로 전달하거나 변수에 저장할 수 있게 된 것이 핵심입니다.
- 핵심 이점: 불필요한 코드를 줄이고(Conciseness), 가독성을 높이며, 행위 자체를 전달할 수 있습니다.
2. 문법 구조: 어떻게 쓰나요?
람다식은 화살표(->)를 중심으로 왼쪽에는 매개변수, 오른쪽에는 실행 블록이 위치합니다.
// 기본 형태
(매개변수) -> { 실행문; }
// 예시: 두 수를 더하는 람다
(a, b) -> { return a + b; }
// 실행문이 하나라면 중괄호{}와 return 생략 가능
(a, b) -> a + b
3. 람다의 전제 조건: 함수형 인터페이스
람다식은 아무 인터페이스나 대체할 수 없습니다. 추상 메서드가 단 하나뿐인 인터페이스만 대체할 수 있는데, 이를 함수형 인터페이스(Functional Interface)라고 부릅니다.
@FunctionalInterface 어노테이션을 붙이면 컴파일러가 메서드가 하나인지 체크해 주어 실수를 방지할 수 있습니다.
@FunctionalInterface
interface Calculator {
int compute(int a, int b);
}
// 실무 활용
Calculator add = (a, b) -> a + b;
System.out.println(add.compute(5, 3)); // 8
4. 자바가 제공하는 4대 표준 함수형 인터페이스
자바는 매번 인터페이스를 만들기 번거로운 개발자들을 위해 표준 인터페이스를 미리 제공합니다. 스트림 API의 모든 메서드는 이 인터페이스들을 기반으로 작동합니다.
- Predicate<T>: T를 받아서 boolean을 반환합니다. (조건 체크용)
- 예: (n) -> n > 10 (스트림의 filter에서 주로 사용)
- Function<T, R>: T를 받아서 R을 반환합니다. (데이터 변환용)
- 예: (user) -> user.getName() (스트림의 map에서 주로 사용)
- Consumer<T>: T를 받아서 소비만 하고 아무것도 반환하지 않습니다.
- 예: (s) -> System.out.println(s) (스트림의 forEach에서 주로 사용)
- Supplier<T>: 아무것도 받지 않고 T를 생성해서 반환합니다.
- 예: () -> new ArrayList<>()
5. 더 짧게! 메서드 참조 (Method Reference)
람다식이 단순히 특정 메서드를 호출하는 기능만 한다면, :: 기호를 사용하여 더 짧게 줄일 수 있습니다.
- 일반 람다: s -> System.out.println(s)
- 메서드 참조: System.out::println
- 일반 람다: (a, b) -> Math.max(a, b)
- 메서드 참조: Math::max
6. 실무 주의사항: Variable Capture
람다식 내부에서 외부 지역 변수를 사용할 때 주의할 점이 있습니다. 람다에서 사용하는 지역 변수는 final이거나 실질적으로 값이 변하지 않는 effectively final 상태여야 합니다.
int number = 10;
Runnable r = () -> System.out.println(number); // OK
number = 20; // 이후에 값을 바꾸면?
// 에러 발생: 람다에서 참조하는 지역 변수는 final이어야 함
이유: 람다는 별도의 스레드에서 실행될 수 있는데, 지역 변수는 스택 영역에 있어 금방 사라지기 때문입니다. 자바는 이를 방지하기 위해 변수의 값을 복사(Capture)해서 사용하는데, 값이 바뀌면 데이터 불일치가 발생할 수 있어 금지하는 것입니다.
7. 결론: 왜 공부해야 할까?
람다식은 단순히 코드를 줄여주는 "예쁜 문법"이 아닙니다. 스트림 API와 결합하여 대량의 데이터를 병렬로 처리하고, 복잡한 비즈니스 로직을 가독성 있게 표현하는 자바의 현대적 프로그래밍 그 자체입니다.
'TECH > 웹개발' 카테고리의 다른 글
| [Java] 메서드 체이닝(Method Chaining) 완벽 가이드: 원리부터 실무 활용까지 (0) | 2026.02.10 |
|---|---|
| [Java] Optional 완벽 가이드: 더 이상 NullPointerException은 없다 (0) | 2026.02.09 |
| [Java] "for문은 이제 그만!" Java Stream API 실무 심화 가이드: 지연 연산부터 병렬 처리까지 (0) | 2026.02.06 |
| 코드 한 줄 안 고치고 기능을 바꾼다고? (SOLID부터 스프링 컨테이너까지) (0) | 2026.01.20 |
| "왜 다형성만으로는 부족할까? SOLID 원칙과 스프링 DI의 본질" (0) | 2026.01.19 |