익명 클래스보다는 람다를 사용하라
- 익명 클래스
Collection.sort(words, new Compareator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
}
- 람다식을 함수 객체로 사용
Collection.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
- 타입을 명시해야 코드가 더 명확할 때를 제외하고는, 람다의 모든 매개변수 타입은 생략하자.
- 람다는 이름이 없고 문서화도 못 한다. 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야 한다.
- 람다를 직렬화하는 일은 극히 삼가야 한다.
람다보다는 메서드 참조를 사용하라
- 메서드 참조가 짧고 명확하다면 메서드 참조를 쓰고, 그렇지 않을 때만 람다를 사용하라.
메서드 참조 유형 |
예 |
같은 기능을 하는 람다 |
정적 |
Integer::parseInt |
str -> Integer.parseInt(str) |
한정적 (인스턴스) |
Instant.now()::isAfter |
Instant then = Instant.now(); t -> then.isAfter(t) |
비한정적 (인스턴스) |
Strubg::toLowerCase |
str -> str.toLowerCase |
클래스 생성자 |
TreeMap<K, V>::new |
() -> new TreeMap<K, V>() |
배열 생성자 |
int[]::new |
len -> new int[len] |
표준 함수형 인터페이스를 사용하라
- 필요한 용도에 맞는 표준 함수형 인터페이스가 있다면, 직접 구현하지 말고 활용하라.
- 기본 함수형 인터페이스에 박싱된 기본 타입을 넣어 사용하지 말자.
- 직접 만든 함수형 인터페이스에는 항상 @FunctionalInterface 애너테이션을 사용하라.
스트림은 주의해서 사용하라
- 스트림을 과용하면 프로그램이 읽거나 유지보수하기 어려워진다.
- char 값들을 처리할 때는 스트림을 삼가하는 편이 낫다.
- 기존 코드는 스트림을 사용하도록 리팩토링하되, 새 코드가 더 나아 보일 때만 반영하자.
스트림에서는 부작용 없는 함수를 사용하라
- foreach 연산은 스트림 계산 결과를 보고할 때만 사용하고, 계산하는 데는 쓰지 말자.
- 스트림 패러다임을 이해하지 못한 경우 (X)
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {
words.foreach(word -> {
freq.merge(word.toLowerCase(), 1L, Long::sun);
});
}
- 스트림을 제대로 활용하는 경우
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
freq = words.collect(groupingBy(String::toLowercCase, counting()));
}
- 스트림을 올바로 사용하려면 수집기를 잘 알아둬야 한다. 가장 중요한 수집기 팩토리는 toList, toSet, toMap, groupingBy, joining 이다.
반환 타입으로는 스트림보다 컬렉션이 낫다
- 원소 시퀀스를 반환하는 메서드의 반환 타입에는 Collection이나 그 하위 타입을 쓰는 게 일반적으로 최선이다.
- 단지 컬렉션을 반환한다는 이유로 덩치 큰 시퀀스를 메모리에 올려서는 안된다.
- 컬렉션을 반환하는게 불가능하면 스트림과 Iterable 중 더 자연스러운 것을 반환하라.
스트림 병렬화는 주의해서 적용하라
- 데이터 소스가 Stream.iterate거나 중간 연산으로 limit을 쓰면 파이프라인 병렬화로는 성능 개선을 기대할 수 없다.
- 스트림의 소스가 ArrayList, HashMap, HashSet, ConcorrentHashMap의 인스턴스거나 배열, int 범위, long 범위일 때 병렬화의 효과가 가장 좋다.
- 스트림을 잘못 병렬화하면 성능이 나빠질 뿐만 아니라 결과 자체가 잘못되거나 예상 못한 동작이 발생할 수 있다. (계산이 정확하고 성능도 좋아졌음이 확실해지면 반영하라.)
- 조건이 잘 갖퉈지면 paraller 메서드 호출 하나로 거의 프로세서 코어 수에 비례하는 성능 향상을 느낄 수 있다.
- 무작위 수들로 이뤄진 스트림을 병렬화하려거든 ThreadLocalRandon(혹은 구식인 Random) 보다는 SplittableRandom 인스턴스를 이용하자.
'책 > Effective Java' 카테고리의 다른 글
일반적인 프로그래밍 원칙 (0) | 2020.03.26 |
---|---|
메서드 (0) | 2020.03.24 |
열거 타입과 애너테이션 (0) | 2020.03.18 |
제네릭 (0) | 2020.03.17 |
클래스와 인터페이스 (0) | 2020.03.14 |