
메서드를 하나의 식으로 표현한 것. 이름이 없는 익명 함수.
메서드를 람다식으로 만드는 방법
int max(int a, int b) {
return a > b ? a : b;
}
-> 를 추가한다.(int a, int b) -> { return a > b ? a : b; }
(int a, int b) -> a > b ? a : b
(a, b) -> a > b ? a : b
람다식은 사실 익명 클래스 객체와 같다.
(int a, int b) -> a > b ? a : b // 이 람다식은
new Object() { // 익명 클래스와 같다.
int max(int a, int b) {
return a > b ? a : b;
}
}
이름도 없는 객체의 메서드를 어떻게 호출할 수 있을까? 함수형 인터페이스를 사용한다.
단 하나의 추상 메서드만 갖고 있는 인터페이스.
람다식을 다루기 위한 참조변수 타입을 함수형 인터페이스로 한다.
@FunctionalInterface // 함수형 인터페이스인지 컴파일러가 확인해줌(필수X)
interface MyFunction {
public abstract int max(int a, int b);
}
MyFunction f = new MyFunction() { // 익명 클래스 선언과 객체 생성 동시에
public int max(int a, int b) { return a > b ? a : b; }
}
MyFunction f = (a, b) -> a > b ? a : b; // 익명 객체를 람다식으로 대체
int big = f.max(5, 3); // 익명 객체의 메서드 호출 가능.
메서드 매개변수 타입이 함수형 인터페이스인 경우 : 매개변수를 람다식으로 받는다.(참조변수 없이 람다식을 직접 매개변수로 지정 가능)
메서드 반환타입이 함수형 인터페이스인 경우 : 람다식 직접 반환 가능
자주 사용되는 함수형 인터페이스를 미리 정의해 놓은 것. 표준화 되어 있어 이해가 쉽고 편리하다.

Predicate는 반환타입이 boolean 이기 때문에 and() , or() , negate() ( 각각 &&, ||, ! ) 로 여러 조건식을 연결할 수 있다.
static 메서드인 isEqual() 로 두 대상을 비교하는 Predicate 를 만들 수 있다.
isEqual() 의 매개변수로 비교 대상을 정하고, 다른 대상은 Predicate의 추상 메서드 test() 의 매개변수로 지정한다.
Predicate<String> p = Predicate.isEqual(str1);
boolean result = p.test(str2);
// 위 두 문장을 하나로 합치면 아래와 같다.
boolean result = Predicate.isEqual(str1).test(str2);
매개변수가 2개인 경우, 이름 앞에 'Bi'가 붙는다.
BiSupplier 는 존재하지 않는다. 반환값은 최대 1개까지만 가능하기 때문.


| 인터페이스 | 메서드 | 설명 |
|---|---|---|
| Collection | boolean removeIf(Predicate<E> filter) | 조건에 맞는 요소 삭제 |
| List | void replaceAll(UnaryOperator<E> operator) | 모든 요소를 변환하여 대체 |
| Iterable | void forEach(Consumer<T> action) | 모든 요소에 작업 action을 수행 |
| Map | V compute(K key, BiFunction<K, V, V> f) | 지정된 키의 값에 작업 f를 수행 |
V computeIfAbsent(K key, Function<K, V> f) | 키가 없으면, 작업 f 수행 후 추가 | |
V computeIfPresent(K key, BiFunction<K, V, V> f) | 지정된 키가 있을 때, 작업 f 수행 | |
V merge(K key, V value, BiFunction<V, V, V> f) | 모든 요소에 병합작업 f를 수행 | |
void forEach(BiConsumer<K, V> action) | 모든 요소에 작업 action을 수행 | |
void replaceAll(BiFunction<K, V, V> f) | 모든 요소에 치환작업 f를 수행 |
람다식을 더 간단히 만든 것. 클래스명::메서드명 으로 작성하면 된다.
Function<String, Integer> f = (String s) -> Integer.parseInt(s); // 람다식
Function<String, Integer> f = Integer::parseInt; // 메서드 참조
생성자를 호출하는 람다식도 메서드 참조로 변환이 가능하다.
Supplier<MyClass> s = () -> new MyClass(); // 람다식
Supplier<MyClass> s = MyClass::new; // 메서드 참조
배열 생성할 때도 메서드 참조를 사용할 수 있다.
Function<Integer, int[]> f = x -> new int[x]; // 람다식
Function<Integer, int[]> f = int[]::new; // 메서드 참조
다양한 데이터 소스를 표준화된 방법으로 다루기 위한 것. 스트림으로 만들기만 하면 똑같은 방식으로 연산을 처리할 수 있다.
기존의 컬렉션 프레임웍은 표준화라는 목적에 완전히 부합하지 못했으나, JDK 1.8 부터 등장한 스트림으로 컬렉션이나 배열과 같은 것들을 표준화된 방식으로 다룰 수 있게 되었다.
stream.distinct().limit(5).sorted().forEach(System.out::println);
forEach() 내부에 숨겨 코드가 간결해진다.parallel() 을 사용하여 연산을 병렬로 처리할 수 있다.sequential() 을 이용한다.Stream<Integer> 에 비해 오토박싱&언박싱의 비효율을 줄일 수 있다.Stream<T> Collection.stream()
Collection 인터페이스의 stream() 메서드로 스트림을 생성한다.
배열을 소스로 하는 스트림.
Stream.of() 와 Arrays.stream() 메서드를 이용하여 생성한다.
IntStream ints()
LongStream longs()
DoubleStream doubles()
이 메서드들은 해당 타입의 난수들로 이루어진 스트림을 반환하는데, '무한 스트림'이므로, limit() 을 함께 사용하여 스트림 크기를 제한해주어야 한다.
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
range() 는 end가 범위에 포함되지 않지만, rangeClosed() 는 end가 범위에 포함된다.
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> generate(Supplier<T> s)
iterate() 와 generate()는 매개변수로 람다식을 받아서 무한 스트림을 생성한다.
iterate()는 초기값(seed)을 시작으로 람다식 f에 의해 계산된 결과를 다시 seed값으로 하여 계산을 반복한다.(이전 요소에 종속적)
generate()는 초기값을 받지 않고, 람다식에 의해 계산된 결과를 요소로 하는 무한스트림을 생성하지만, 이전 결과를 이용해서 다음 요소를 계산하지 않는다.(이전 요소에 독립적)
Stream<Path> Files.list(Path.dir)
파일의 목록을 소스로 하는 스트림.
Stream.empty()를 이용하여 요소가 하나도 없는 빈 스트림을 생성할 수도 있는데, 스트림 연산 수행 결과가 하나도 없을 때, null 보다 빈 스트림을 반환하는 것이 낫다.