이펙티브자바 정리 6
42. 익명 클래스보다는 람다를 사용하라
- 타입을 명시해야 코드가 더 명확할 때를 제외하고는 람다의 모든 매개변수 타입은 생략해라
Collections.sort(words, new Comparator<Strin>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
를 람다로 변환
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
- 람다는 이름이 없고 문서화도 못함으로 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄이 많아지면 쓰지말아야 한다
- 람다를 직렬화 하지 말아라
- 익명 클래스는 타입의 인스턴스를 만들 떄만 사용해라
43. 람다보다는 메서드 참조를 사용해라
map.merge(key, 1, (count, incr) -> count + incr);
람다로 변환
map.merge(key, 1, Integer::sum);
- merge 메서드는 키, 값, 함수를 인자로 받음
- 키가 맵 안에 없다면 주어진 키, 값을 그대로 쌍으로 저장
- 키가 존재 한다면 세번째 인수로 받은 함수에 현재 값과 주어진 값을 적용시키고 그 결과값은 저장
메서드 참조 유형
44. 표준 함수형 인터페이스를 사용해라
- 필요한 용도에 맞다면 직접 구현하지말고 표준함수형 인터페이스를 참조해라
- 직접 만든 함수형 인터페이스에는 항상 @FunctionalInterface 에너테이션을 사용해라
45. 스트림은 주의해서 사용해라
스트림 API가 제공하는 추상 개념
- 스트림 : 무한시퀀스
- 스트림 파이프라인 : 원소들로 수행하는 연산 단계 표현
public class Anagrams {
public static void main(String[] args) throws FileNotFoundException {
File dictionary = new File(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
Map<String, Set<String>> groups = new HashMap<>();
try (Scanner s = new Scanner(dictionary)) {
while (s.hasNext()) {
String word = s.next();
groups.computeIfAbsent(alphabetize(word),
(unused) -> new TreeSet<>()).add(word);
}
}
for (Set<String>group : groups.values())
if (group.size() >= minGroupSize)
System.out.println(group.size() + ": " + group);
}
private static String alphabetize(String s){
char[] a = s.toCharArray();
Arrays.sort(a);
return new String(a);
}
}
computeIfAbsent : 맵 안에 키가 있는지 찾고 있으면 단순 매핑값 반환, 키 없으면 건네진
함수 객체를 키에 적용하고 값을 계산 후 그 키와 매핑한 후 값을 반환
위 코드를 스트림을 이용하여 변환
public class AnagramStream {
public static void main(String[] args) throws IOException {
Path dictionary = Paths.get(args[0]);
int minGroupSize = Integer.parseInt(args[1]);
try (Stream<String>words = Files.lines(dictionary)){
words.collect(groupingBy(word -> alphabetize(word)))
.values().stream()
.filter(group -> group.size() >= minGroupSize)
.forEach(g -> System.out.println(g.size() + ": " + g));
}
}
}
위 코드는 중간 연산은 없고, 종단 연산에서 모든 단어를 수집해 맵으로 모은다
스트림을 사용하면 좋은 경우
- 원소들의 시퀀스를 일관되게 반환
- 원소들의 시퀀스를 필터링
- 원소들의 시퀀스를 하나의 연산을 사용해 결합
- 원소들의 시퀀스를 컬렉션에 모음
- 원소들의 시퀀스에서 특정 조건을 만족하는 원소를 찾음
46. 스트림에서는 부작용 없는 함수를 사용해라
스트림 패러다임의 핵심 : 계산을 일련의 변환으로 재구성함
→ 각 단계는 이전 단계의 결과를 받아 처리하는 순수함수여야 한다
순수함수 : 오직 입력만이 결과에 영향을 주는 함수
잘못 사용된 스트림
public class wrong {
Map<String, Long> freq = new HashMap<>();
try (Stream<String> words = new Scanner(file).tokens()) {
words.forEach(word -> {
freq.merge(word.toLowerCase(), 1L, Long::sum);
});
}
}
- forEach로 인한 반복적 코드
- 모든 종단 작업이 forEach에서 일어남
- 이때 외부 상태를 수정하는 람다가 (Long::sum)이 실행되면서 문제가 생김
제대로 사용된 스트림
public class Correct {
Map<String, Long> freq;
try (Stream<String> words = new Scanner(file).tokens()) {
freq = words
.collect(groupingBy(String::toLowerCase, counting()));
}
}
47. 반환 타입으로는 스트림보다 컬렉션이 낫다
48. 스트림 병렬화는 주의해서 적용해라
Author And Source
이 문제에 관하여(이펙티브자바 정리 6), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@kurikuri/이펙티브자바-정리-6저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)