람다식은 “익명 함수(anonymous function)” — 즉, 이름 없는 함수예요.
클래스를 만들지 않고, 함수를 바로 전달할 수 있게 해줍니다.
(매개변수) -> { 실행문 }
예를 들어 👇
(int a, int b) -> { return a + b; }
또는 더 간단히 👇
(a, b) -> a + b
람다식은 불필요한 익명 클래스(Anonymous Class)를 줄이기 위해 등장했어요.
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("작업 실행!");
}
};
Runnable task = () -> System.out.println("작업 실행!");
✅ 훨씬 짧고 가독성 좋음
✅ 객체 대신 “함수” 자체를 전달 가능
| 구성 | 설명 | 예시 |
|---|---|---|
| 매개변수 목록 | 함수의 입력값 | (x, y) |
화살표 -> | 매개변수와 본문을 구분 | (x, y) -> x + y |
| 실행문 | 수행할 코드 | { return x + y; } 또는 x + y |
| 형태 | 예시 | 설명 |
|---|---|---|
| 매개변수 없음 | () -> System.out.println("Hi") | Runnable 등에 사용 |
| 매개변수 1개 | x -> x * x | 괄호 생략 가능 |
| 여러 개 | (x, y) -> x + y | 괄호 필수 |
| 실행문 여러 개 | (x, y) -> { int sum = x + y; return sum; } | {}와 return 필요 |
람다는 독립적으로 존재할 수 없습니다.
자바에서는 반드시 추상 메서드가 1개만 있는 인터페이스(Functional Interface)에 연결되어야 합니다.
예를 들어 👇
@FunctionalInterface
interface MyFunction {
void sayHello();
}
이 인터페이스를 람다로 구현할 수 있습니다:
MyFunction f = () -> System.out.println("Hello!");
f.sayHello(); // Hello!
즉,
람다는 “함수의 구현 부분”이고
펑션 인터페이스는 “그 함수를 담는 틀”이에요.
| 인터페이스 | 추상 메서드 | 설명 | 예시 |
|---|---|---|---|
| Runnable | void run() | 스레드 작업 등 | () -> System.out.println("작업!") |
| Consumer | void accept(T t) | 입력 받고 처리만 | s -> System.out.println(s) |
| Supplier | T get() | 입력 없이 리턴만 | () -> Math.random() |
| Function<T,R> | R apply(T t) | 입력을 가공해 반환 | x -> x * 2 |
| Predicate | boolean test(T t) | 조건 검사 | n -> n > 0 |
| 상황 | 사용 예 | 설명 |
|---|---|---|
| ✅ Stream API | list.stream().filter(x -> x>10).forEach(System.out::println); | 데이터 필터링, 매핑 |
| ✅ 이벤트 처리 (GUI) | button.addActionListener(e -> System.out.println("클릭!")); | 익명 클래스 대신 간결하게 |
| ✅ 스레드 실행 | new Thread(() -> System.out.println("Thread run!")).start(); | Runnable 대체 |
| ✅ 정렬 | list.sort((a, b) -> a.compareTo(b)); | Comparator 대신 |
| 장점 | 설명 |
|---|---|
| ✅ 코드 간결성 | 익명 클래스보다 훨씬 짧고 직관적 |
| ✅ 가독성 향상 | 의도가 명확하게 드러남 |
| ✅ 함수형 프로그래밍 가능 | Stream API, 메서드 체이닝 등 |
| ✅ 재사용성 증가 | 함수를 값처럼 변수로 전달 가능 |
| 항목 | 주의 내용 |
|---|---|
| ❌ 상태 변경 지양 | 람다는 가급적 “순수 함수”로 설계해야 함 |
| ❌ this 키워드 | 람다 내부의 this는 “람다 자신”이 아니라 “바깥 클래스”를 가리킴 |
| ❌ checked 예외 처리 | 람다 내부에서 예외를 던질 때는 직접 try-catch 필요 |
import java.util.*;
import java.util.function.*;
public class LambdaExample {
public static void main(String[] args) {
// 1. Runnable
Runnable r = () -> System.out.println("스레드 실행!");
new Thread(r).start();
// 2. Predicate
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
// 3. Function
Function<String, Integer> lengthFunc = s -> s.length();
System.out.println(lengthFunc.apply("Java")); // 4
// 4. Consumer
Consumer<String> printer = s -> System.out.println("출력: " + s);
printer.accept("Lambda!");
// 5. Stream API 활용
List<Integer> list = Arrays.asList(1,2,3,4,5);
list.stream()
.filter(n -> n % 2 == 1)
.map(n -> n * n)
.forEach(System.out::println);
}
}
람다식(Lambda) = 이름 없는 함수
펑션 인터페이스 = 람다를 담는 틀
👉 자바에서 “함수를 값처럼” 다루게 해주는 문법
람다는 코드를 더 간결하게 도와주는 고마운 장치다