프로그래밍 패러다임 중 하나로, "함수(function)" 를 일급 시민(first-class citizen)으로 간주하며, 데이터의 상태 변화보다는 함수의 조합과 계산에 집중하는 방식을 뜻함.
int add(int a, int b) {
return a + b; // 외부 상태를 변경하지 않음
}
filter, map, reduce 등stream()으로 처리.// Before Java 8
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};
// After Java 8 (Lambda)
Comparator<String> comparator = (s1, s2) -> s1.length() - s2.length();
List<String> names = Arrays.asList("AAA", "Bb", "C");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
Function, Predicate, Consumer, Supplier가독성과 유지보수성 증가:
병렬 처리 및 성능 향상:
에러 감소:
현대 프로그래밍 트렌드에 부합:
(parameters) -> expression
{} 가능)Runnable r = () -> System.out.println("람다 표현식이다.");
r.run();
Consumer<String> printer = message -> System.out.println(message);
printer.accept("자바 람다, 쉽다.");
BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b;
System.out.println(sum.apply(10, 20)); // 출력: 30
Function<Integer, Integer> square = x -> {
int result = x * x;
return result;
};
System.out.println(square.apply(5)); // 출력: 25
익명 클래스:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a - b;
}
};
람다 표현식:
Comparator<Integer> comparator = (a, b) -> a - b;
| 특징 | 익명 클래스 | 람다 표현식 |
|---|---|---|
| 문법 | 복잡하고 장황함 | 간결하고 직관적 |
| 클래스 생성 | 새로운 익명 클래스 생성 | 기존 함수형 인터페이스를 구현 |
| this 키워드 | 익명 클래스 자신을 가리킴 | 람다 표현식이 정의된 외부 클래스를 가리킴 |
람다 표현식은 함수형 인터페이스와 함께 사용됨.
Function<T, R>:
Function<Integer, String> intToString = num -> "Number: " + num;
System.out.println(intToString.apply(5)); // 출력: Number: 5
Consumer:
Consumer<String> printer = message -> System.out.println(message);
printer.accept("함수형 인터페이스!");
Predicate:
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // 출력: true
Supplier:
Supplier<Double> random = () -> Math.random();
System.out.println(random.get());
람다 표현식은 익명 클래스의 복잡함을 줄이고 함수형 프로그래밍을 쉽게 구현할 수 있게 해주는 핵심 요소.
함수형 인터페이스와의 연계를 통해 실무에서 반복 작업을 간소화하고, 더 읽기 좋은 코드를 작성할 수 있다.
람다 표현식은 코드의 간결성과 가독성을 높이는 데 매우 유용하지만, 몇 가지 한계와 주의점이 있음.
복잡한 로직에 부적합:
// 복잡한 로직이 람다에 포함된 예 (비추천)
list.stream()
.filter(item -> {
// 여러 조건을 확인하는 복잡한 코드
if (item.isActive() && item.getValue() > 10) {
return true;
}
return false;
});
// 복잡한 로직은 메서드로 분리 (추천)
list.stream()
.filter(this::isValidItem);
private boolean isValidItem(Item item) {
return item.isActive() && item.getValue() > 10;
}
디버깅의 어려움:
성능 이슈:
익명 클래스와의 차이점:
함수형 인터페이스를 정확히 이해해야 함:
고객 이름 리스트에서 'A'로 시작하는 이름만 필터링:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Aaa", "Bbb", "Ccc", "AAA");
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
System.out.println(filteredNames); // 출력: [Aaa, AAA]
}
}
숫자 리스트를 문자열로 변환하고, 모든 값에 접두사 추가:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MappingExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> mapped = numbers.stream()
.map(num -> "Number: " + num)
.collect(Collectors.toList());
System.out.println(mapped); // 출력: [Number: 1, Number: 2, ...]
}
}
import java.util.Arrays;
import java.util.List;
public class SumExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.reduce(0, Integer::sum);
System.out.println(sum); // 출력: 15
}
}
이름을 길이 순서로 정렬:
import java.util.Arrays;
import java.util.List;
public class ComparatorExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("CCCCCC", "BBBB", "Bb");
// 람다 표현식으로 Comparator 간소화
names.sort((a, b) -> a.length() - b.length());
System.out.println(names); // 출력: [Bb, BBBB, CCCCCC]
}
}
쓰레드 실행 로직 간결화:
public class RunnableExample {
public static void main(String[] args) {
// 기존 방식
Runnable oldRunnable = new Runnable() {
@Override
public void run() {
System.out.println("Runnable 방식!");
}
};
// 람다 표현식
Runnable newRunnable = () -> System.out.println("람다로 간소화된 Runnable!");
oldRunnable.run();
newRunnable.run();
}
}
버튼 클릭 이벤트 처리:
import javax.swing.JButton;
public class EventHandlerExample {
public static void main(String[] args) {
JButton button = new JButton("클릭하세요");
// 람다 표현식으로 이벤트 핸들러 작성
button.addActionListener(e -> System.out.println("버튼이 클릭되었다!"));
}
}
조건에 따라 필터링하고 정렬:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FilterSortExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> result = names.stream()
.filter(name -> name.length() > 3)
.sorted()
.collect(Collectors.toList());
System.out.println(result); // 출력: [Alice, Charlie, David]
}
}