본문 바로가기

책/Effective Java

람다와 스트림

익명 클래스보다는 람다를 사용하라

 - 익명 클래스

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