아이템 42. 익명클래스보다 람다를 사용하라
- 람다는 이름 없고, 문서화 불가능. 명확하지 않고, 라인이 많으면 람다 사용 X
- 람다가 대체할 수 없어 익명클래스를 사용해야 하는 곳
1. 람다는 함수형 인터페이스에서만 쓰임
추상 클래스의 인스턴스를 만들 때 람다를 쓸 수 없음
추상 메서드가 여러 개인 인터페이스의 인스턴스를 만들 때도 익명 클래스
2. 람다는 자신을 참조할 수 없다.
this 쓰면 바깥 인스턴스를 가리킴. 익명클래스는 자신을 가리킴.
아이템 43. 람다보다는 메서드 참조를 사용하라
- 람다를 대신하여 메서드 참조라는 기능을 사용하여 더 명확하게 표현할 수 있다.
- 하지만 람다가 더 가독성이 좋을 때도 있으니, 잘 사용하자
ex. 메서드와 람다가 같은 클래스에 있을 때
- 한정적 메서드 참조가 조금 이해가 어려웠는데, 한정적 메서드 참조는 인스턴스에 함수의 결과값의 메서드를 참조하는 것이다.
LocalDate targetDate = LocalDate.now();
Predicate<LocalDate> localDateUnaryOperator = targetDate.minusDays(1)::isAfter;
assertThat(localDateUnaryOperator.test(targetDate)).isFalse();
아이템 44. 표준 함수형 인터페이스를 사용하라
- java.util.function 패키지에 다양한 용도의 표준 함수형 인터페이스가 있다. 용도에 맞는 게 있다면 표준을 활용하자
- Function, Operator, Predicate, Consumer, Supplier만 잘 알아두자 (나머지는 변형이라 필요할 때 찾아서 쓰면 됨)
- 박싱된 기본 타입 넣어서 쓰지 말자
- 함수형 인터페이스를 직접 만들어야한다면, 반드시
@FunctionalInterface
를 붙이자
아이템 45. 스트림은 주의해서 사용하라
- 스트림은 지연 평가되므로 반드시 종단 연산이 있어야 한다.
- 기본적으로 순차적으로 수행되므로, 병렬이 필요하면 parallel을 사용하면 되는데, 성능 효과 크지 않아서 굳이..?
- 람다 안에서는 final or effectively final 변수만 읽을 수 있다.
- 스트림 파이프라인은 한 값을 다른 값에 매핑하고 나면 원래 값을 잃는 구조다.
- 스트림, 반복문 둘다 해보고, 더 나아보이는 쪽을 쓰자
아이템 46. 스트림에는 부작용 없는 함수를 사용하라
- 스트림 패러다임의 핵심은 계산을 일련의 변환으로 재구성하는 부분이다. (순수 함수)
스트림 연산에 건내는 함수 객체는 모두 side-effect가 없어야 한다.
- 스트림의
forEach
는 종단 연산 중 가장 덜 스트림스럽다.
- 스트림을 잘 사용하려면 수집기를 잘 알아둬야 한다.
Collectors
에 있는 메서드 중 중요한 것은 잘 알아두자
아이템 47. 반환 타입으로는 스트림보다 컬렉션이 낫다.
- 반환타입으로 스트림보다 컬렉션이 나은 이유
둘다 iterable을 구현하고 있지만, 스트림은 iterable을 extend하지 않아서 loop문이 정상적으로 동작 되지 않음
그래서 스트림으로 반환하면 반복하기 위해서는 무조건 forEach문을 사용해야함
- Collection 인터페이스는 Iterable의 하위 타입이고 Stream도 동시에 사용할 수 있음
그래서 API의 반환타입은 Collection 이나 하위타입을 쓰는 것이 일반적으로 최선
- 직접 전용 컬렉션을 구현해서 쓰는 방법도 있다.
아이템 48. 스트림 병렬화는 주의해서 사용하라.
- 데이터 소스가 Stream.iterate거나 중간 연산으로 limit 쓰는 경우 병렬화로 성능 개선 어려움
- ArrayList, HashMap, HashSet, ConcurrentHashMap, 배열, int 범위, long 범위일 때 병렬화 효과 좋음 (아래의 이유로)
1. 데이터를 원하는 크기로 정확, 쉽게 나눌 수 있음
2. 참조 지역성
- 종단 연산 중 reduction이 병렬화에 가장 적합함
collect 같은 가변 축소는 아님
- 잘못 쓰면 성능 문제, 오동작할 수 있으니 항상 성능 테스트하고 쓰자!