본문 바로가기

독서찰기(讀書札記)

(90)
[아이템 45] 스트림은 주의해서 사용하라 스트림이란? 스트림 API는 다량의 데이터 처리 작업(순차적이든 병렬적이든)을 돕고자 자바 8에 추가되었다. 스트림 API가 제공하는 추상 개념 중 핵심은 두 가지다. 첫 번째, 스트림(stream)은 데이터 원소의 유한 혹은 무한 시퀀스(sequence)를 뜻한다. 두 번째, 스트림 파이프라인(stream pipeline)은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림 안의 데이터 원소들은 객체 참조나 기본 타입 값이다. 기본 타입 값으로는 int, long, double 이렇게 세 가지를 지원한다. 스트림 API는 메서드 연쇄를 지원하는 플루언트 API(fluent API)다. 스트림 파이프라인 스트림 파이프라인은 소스 스트림에서 시작해 종단 연산(terminal operation)으..
[아이템 44] 표준 함수형 인터페이스를 사용하라 @FunctionalInterface Functional Interface는 구현해야 할 추상 메소드가 하나만 정의된 인터페이스를 가리킨다. [Why] 자바가 람다를 지원하면서 API를 작성하는 모범 사례도 크게 바뀌었다. 예컨대 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 메서드 패턴의 매력이 크게 줄었다. 이를 대체하는 현대적인 해법은 같은 효과의 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 것이다. 따라서 함수 객체를 매개변수로 받는 생성자와 메서드를 많이 만들어야 한다. 이때 함수형 매개변수 타입을 올바르게 선택해야 한다. protected boolean removeEldestEntry(Map.Entry eldest) { return size() > 100; } // ..
[아이템 43] 람다보다는 메서드 참조를 사용하라 [Why] 람다가 익명 클래스보다 나은 점 중에서 가장 큰 특징은 간결함이다. 그런데 자바에는 함수 객체를 심지어 람다보다도 더 간결하게 만드는 방법이 있으니, 바로 메서드 참조(method reference)다. map.merge(key, 1, (count, incr) -> count + incr); 위 코드는 임의의 키와 Integer 값의 매핑을 관리하는 프로그램의 일부다. 이 코드는 자바 8 때 Map에 추가된 merge 메서드를 사용했다. merge 메서드는 키, 값, 함수를 인수로 받으며, 주어진 키가 맵 안에 아직 없다면 주어진 {키, 값} 쌍을 그대로 저장한다. 반대로 키가 이미 있다면 세 번째 인수로 받은 함수를 현재 값과 주어진 값에 적용한 다음, 그 결과로 현재 값을 덮어쓴다. 즉, ..
[아이템 42] 익명 클래스보다는 람다를 사용하라 ※ 예전에는 자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스(드물게는 추상 클래스)를 사용했다. 이런 인터페이스의 인스턴스를 함수 객체(function object)라고 하여, 특정 함수나 동작을 나타내는 데 썼다. 1997년 JDK 1.1이 등장하면서 함수 객체를 만드는 주요 수단은 익명 클래스(아이템24)가 되었다. [Why] Collections.sort(words, new Comparator() { public int compare(String s1, String s2) { return Integer.compare(s1.length(), s2.length()); } }); 익명 클래스 방식은 코드가 너무 길기 때문에 자바는 함수형 프로그래밍에 적합하지 않았다. [When] 람..
[아이템 37] ordinal 인덱싱 대신 EnumMap을 사용하라 [Why] 배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드(아이템35)로 인덱스를 얻는 코드가 있다. class Plant { enum LifeCycle { ANNUAL, PERENNIAL, BIENNIAL } final String name; final LifeCycle lifeCycle; Plant(String name, LifeCycle lifeCycle) { this.name = name; this.lifeCycle = lifeCycle; } @Override public String toString() { return name; } } 이제 정원에 심은 식물들을 배열 하나로 관리하고, 이들을 생애주기(한해살이, 여러해살이, 두해살이)별로 묶어보자. Set[] plantsByLifeCyc..
[아이템 36] 비트 필드 대신 EnumSet을 사용하라 [Why] public class Text { public static final int STYLE_BOLD = 1
[아이템 35] ordinal 메서드 대신 인스턴스 필드를 사용하라 ordinal 메서드란? 대부분의 열거 타입 상수는 자연스럽게 하나의 정숫값에 대응된다. 그리고 모든 열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal이라는 메서드를 제공한다. [Why] 열거 타입 상수와 연결된 정숫값이 필요하면 ordinal 메서드를 이용하고 싶은 유혹에 빠진다. public enum Ensemble { SOLO, DUET, TRIO, QUARTET, QUINTET, SEXTET, SEPTET, OCTET, NONET, DECTET; public int numberOfMusicians() { return ordinal() + 1; } } 상수 선언 순서를 바꾸는 순간 numberOfMusicians가 오동작하며, 이미 사용 중인 정수와 값이 같은 상..
[아이템 34] int 상수 대신 열거 타입을 사용하라 [Why] public static final int APPLE_FUJI = 0; public static final int APPLE_PIPPIN = 1; public static final int APPLE_GRANNY_SMITH = 2; public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2; 정수 열거 패턴(int enum pattern) 기법에는 단점이 많다. 타입 안전을 보장할 방법이 없다. 오렌지를 건네야 할 메서드에 사과를 보내고 동등 연산자(==)로 비교하더라도 컴파일러는 아무런 경고 메시지를 출력하지 않는다. 자바가 정..