EffectiveJava
-
[Effective Java] 매개변수가 유효한지 검사하라Java 2023. 2. 3. 10:27
매개변수가 유효한지 검사하라 메서드와 생성자 대부분은 입력 매개변수의 값이 특정 조건을 만족하기를 바란다. 인덱스 값은 음수이면 안 되며, 객체 참조는 null이 아니어야 하는 식이다. 이런 제약은 반드시 문서화해야 하며 메서드 몸체가 시작되기 전에 검사해야 한다. 이는 "오류는 가능한 한 빨리 (발생한 곳에서) 잡아야 한다"는 일반 원칙의 한 사례이기도 하다. 메서드 몸체가 실행되기 전에 매개변수를 확인한다면 잘못된 값이 넘어왔을 때 즉각적이고 깔끔한 방식으로 예외를 던질 수 있다. 매개변수 검사를 제대로 하지 못하면 생기는 문제 메서드가 수행되는 중간에 모호한 예외를 던지며 실패할 수 있다. 더 나쁜 상황은 메서드가 잘 수행되지만 잘못된 결과를 반환할 때다. 한층 더 나쁜 상황은 메서드는 문제없이 수..
-
[Effective Java] 스트림 병렬화는 주의해서 적용하라Java 2023. 2. 3. 10:26
자바는 동시성 프로그래밍 측면에서 항상 앞서갔다. 처음 릴리즈된 1996년부터 스레드, 동기화, wait/notify를 지원했다. 자바 5부터는 동시성 컬렉션인 java.util.concurrent 라이브러리와 실행자(Executor) 프레임워크를 지원했다. 자바 7부터는 고성능 병렬 분해 프레임워크인 포크-조인(fork-join) 패키지를 추가했다. 자바 8부터는 parallel 메서드만 한 번 호출하면 파이프라인을 병렬 실행할 수 있는 스트림을 지원했다. 이처럼 자바로 동시성 프로그램을 작성하기가 점점 쉬워지고는 있지만, 이를 올바르고 빠르게 작성하는 일은 여전히 어려운 작업이다. 동시성 프로그래밍을 할 때는 안전성과 응답 가능 상태를 유지하기위해 애써야 한다. 파이프라인 병렬화가 불가능한 경우 예)..
-
[Effective Java] 반환 타입으로는 스트림보다 컬렉션이 낫다Java 2023. 2. 3. 10:25
원소 시퀀스, 즉 일련의 원소를 반환하는 메서드는 수없이 많다. 자바 7까지는 이런 메서드의 반환 타입으로 Collection, Set, List 같은 컬렉션 인터페이스, 혹은 Iterable이나 배열을 썼다. 이 중 가장 적합한 타입을 선택하기란 그다지 어렵지 않았다. for-each 문에서만 쓰이거나 반환된 원소 시퀀스가 일부 Collection 메서드를 구현할 수 없을 때는 Iterable 인터페이스를 썼다. 반환 원소들이 기본 타입이거나 성능에 민감한 상황이라면 배열을 썼다. 스트림은 반복을 지원하지 않는다. 그런데 자바 8이 스트림이라는 개념을 들고 오면서 이 선택이 아주 복잡한 일이 되었다. 스트림은 반복(iteration)을 지원하지 않는다. 따라서 스트림과 반복을 알맞게 조합해야 좋은 코드..
-
[Effective Java] 스트림에서는 부작용 없는 함수를 사용하라Java 2023. 2. 3. 10:24
스트림은 처음 봐서는 이해하기 어려울 수 있다. 원하는 작업을 스트림 파이프라인으로 표현하는 것조차 어려울지 모른다. 성공하여 프로그램이 동작하더라도 장점이 무엇인지 쉽게 와 닿지 않을 수도 있다. 단순 API가 아닌 함수형 프로그래밍에 기초한 패러다임이기 때문이다. 스트림 패러담의 핵심은 계산을 일련의 변환으로 재구성하는 부분이다. 이때 각 변환 단계는 가능한 한 이전 단계의 결과를 받아 처리하는 순수 함수여야 한다. 순수 함수란 오직 입력만이 결과에 영향을 주는 함수를 말한다. 다른 가변 상태를 참조하지 않고, 함수 스스로도 다른 상태를 변경하지 않는다. 이렇게 하려면 스트림 연산에 건네는 함수 객체는 모두 부작용이 없어야 한다. 안좋은 예시 다음은 주위에서 종종 볼 수 있는 스트림 코드로, 텍스트 ..
-
[Effective Java] 스트림은 주의해서 사용하라Java 2023. 2. 2. 11:08
스트림 API는 다량의 데이터 처리 작업(순차적이든 병렬적이든)을 돕고자 자바 8에 추가되었다. 이 API가 제공하는 추상 개념 중 핵심은 두 가지다. 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 뜻한다. 스트림 파이프라인은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림 원소들은 어디로부터든 올 수 있다. 대표적으로는 아래와 같은 것들이 있다. 컬렉션 배열 파일 정규표현식 난수 생성기 다른 스트림 스트림 안의 데이터 원소들은 객체 참조나 기본 타입(int, long, double)을 지원한다. Stream : 객체 참조타입에 대한 Stream IntStream: int 타입에 대한 Stream LongStream: long 타입에 대한 Stream DoubleStrema: double ..
-
[Effective Java] 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라Java 2023. 2. 2. 11:07
열거 타입은 거의 모든 상황에서 타입 안전 열거 패턴보다 우수하다. 단, 타입 안전 열거 패턴은 확장할 수 있으나 열거 타입은 그럴 수 없다는 예외가 하나 있다. 확장 불가능한 열거 타입 열거 타입은 열거한 값들을 그대로 가져온 다음 값을 더 추가하여 다른 목적으로 사용할 수 없다. 즉, 확장이 불가능하다. 열거 타입이 확장 불가능하도록 설계한 이유는 다음과 같다. 확장한 타입의 원소는 기반 타입의 원소로 취급하지만 그 반대는 성립하지 않는 것은 이상하다. 기반 타입과 확장된 타입들의 원소 모두를 순회할 방법도 마땅치 않다. 확장성을 높이려면 고려할 요소가 늘어나 설계와 구현이 더 복잡해진다. 인터페이스를 이용해 확장 가능 열거 타입 흉내내기 확장할 수 있는 열거 타입을 활용하기 좋은 연산코드를 구현해보..
-
[Effective Java] ordinal 인덱싱 대신 EnumMap을 사용하라Java 2023. 2. 2. 11:07
이따금 배열이나 리스트에서 원소를 꺼낼 때 ordinal 메서드로 인덱스를 얻는 코드가 있다. 식물의 생애주기를 열거 타입으로 표현한 예를 살펴보자. public 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; } } ordinal 인덱싱의 단점 정원에 심은 식물들을 배열 하나로 관리하고, 이들을 생애주기(한해살이, ..
-
[Effective Java] int 상수 대신 열거 타입을 사용하라Java 2023. 2. 2. 11:06
열거 타입은 일정 개수의 상수 값을 정의한 다음, 그 외의 값은 허용하지 않는 타입이다. 사계절, 태양계의 행성, 카드게임의 카드 종류 등이 좋은 예다. 자바에서 열거 타입을 지원하기 전에는 다음 코드처럼 정수 상수를 한 묶음 선언해서 사용하곤 했다. 정수 열거 패턴 - 상당히 취약하다. 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 i..