2023. 4. 4. 13:00ㆍ스터디/이펙티브 자바 스터디
아이템 1. 생성자 대신 정적 팩터리 메서드를 고려하라
## 정적 팩터리 메서드 장점
1. 이름을 가질 수 있음 : 반환될 객체에 특성을 쉽게 묘사
2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 됨 : 같은 객체가 자주 요청되는 상황에 성능 향상
3. 반환 타입의 하위 타입 객체를 반환할 수 있음
4. 입력 매개변수에 따라 매번 다른 클래스 객체 반환 가능
5. 정적 팩터리 메서드를 작성하는 시점에서 반환할 객체의 클래스가 존재하지 않아도 됨
## 정적 팩터리 메서드 단점
1. 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없음. 생성자가 private이기 때문
2. 정적 팩터리 메서드는 프로그래머가 찾기어려움. api 문서화 필수
아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라
- 생성자로는 선택적 매개변수가 많으면 적절히 대응하기 어려움
- 점층적 생성자 패턴도 쓸 수 있으나, 매개변수 개수가 많아지면 클라이언트 코드를 작성하거나 읽기 어려움
- 자바빈즈 패턴도 쓸 수 있으나, 객체 하나를 만들려면 여러 개의 매서드 호출해야하고, 객체 완성 전에는 일관성이 무져 있음. 심지어 불편 클래스로 만들 수도 없음
public class Sample {
private final int a;
private final int b;
private final int c;
private final int d;
public static class Builder {
//필수
private final int a;
private final int b;
//선택
private int c = 0;
private int d = 0;
public Builder(int a, int b) {
this.a = a;
this.b = b;
}
public Builder c(int val) {
c = val;
return this;
}
public Builder d(int val) {
d = val;
return this;
}
public Sample build() {
return new Sample(this);
}
}
private Sample(Builder builder) {
a = builder.a;
b = builder.b;
c = builder.c;
d = builder.d;
}
}
- 불변식을 보장하려면 빌더로부터 매개변수를 복사한 수 해당 객체 필드들도 검사
- 불변식 : 프로그램이 실행하는 동안, 혹은 정해진 기간 동안 반드시 만족해야 하는 조건
- 빌더 패턴은 계층적 설계 클래스와 함께 쓰기도 좋음
- 공변 반환 타이핑 : 하위 클래스의 메서드가 상위 클래스의 메서드가 정의한 반환 타입이 아닌, 그 하위 타입을 반환하는 기능
- 빌더 패턴은 성능에 민감한 상황에서는 문제가 될 수도
아이템 3. private 생성자나 열거 타입으로 싱글턴임을 보증하라
- 싱글턴 : 인스턴스를 오직 하나만 생성할 수 있는 클래스
- 싱글턴은 테스트 하기가 어려움. mock 대체가 불가하기 때문
- 정적 팩터리 메서드와 응용 가능 : 싱글톤 여부 설정 가능 및 제네릭 싱글턴 팩터리로 생성 가능
- 아주 복잡한 직렬화 상황이나 리플렉션 공격에도 제 2의 인스턴스가 생기는 일을 완벽히 막아줌
- 대부분 상황에서는 Enum이 싱글턴을 만드는 가장 좋은 방법
아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라
- private 생성자를 통해 클래스의 인스턴스화를 막을 수 있음
- 어떤 환경에서도 클래스가 인스턴스화 되는 것을 막아줌
아이템 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
- 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않음
- DI : 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식
- 팩터리 : 호출할 때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체
아이템 6. 불필요한 객체 생성을 피하라
- 생성자는 호출할 때마다 새로운 객체를 생성, 팩터리 메서드는 그렇지 않음
- 인스턴스를 클래스 초기화(정적 초기화) 과정에서 직접 생성해 캐싱해두고, 나중에 호출시 재사용하는 방식으로 진행 : private static final 붙여서 생성
- 성능 뿐 아니라 코드도 명확해짐 : 이름을 지어주어 코드의 의미가 잘 드러남
- 지연 초기화로 불필요한초기화를 없앨 수 있으나, 코드가 복잡해지고, 성능은 크게 개선 안됨
- 어댑터 : 실제 작업은 뒷단 객체에 위임하고, 자신은 제 2의 인터페이스 역할을 해주는 객체
- 오토박싱 : 기본 타입과 그에 대응하는 박싱된 기본 타입을 상호 변환해줌
- 박싱 타입은 연산시 속도가 느림
- 박싱된 기본 타입 보다는 기본타입을 사용, 의도치 않은 오토박싱이 숨어들지 않도록 주의
- 단순히 객체 생성을 피하고자 객체 풀 생성 X, 자체 객체 풀은 코드를 헷갈리게 만들고, 메모리 사용량을 늘리고 성능을 떨어뜨림
- 방어적 복사가 필요한 상황에서 객체를 재사용했을 때의 피해가 필요 없는 객체를 반복 생성했을 때의 피해보다 훨씬 크다
아이템 7. 다 쓴 객체 참조를 해제하라
- 다 쓴 참조를 여전히 가지고 있으면 GC가 회수를 하지 않음
- 해당 참조를 다 썼을 때 null 처리 하면 됨, 허나 null로 직접 처리하는 일은 예외적인 경우여야 함
- 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 메모리 누수에 주의해야
- 캐시 또한 메모리 누수를 일으키는 주범
- 리스너나 콜백 또한 마찬가지, 콜백 등록만 하고 명확히 해지하지 않으면 계속 쌓임
아이템 8. finalizer와 cleaner 사용을 피하라
- finalizer, cleaner 둘 다 예측 불가, 느리고, 일반적으로 불필요
- 즉시 수행된다는 보장도 없음. GC에서 다른 애플리케이션 스레드보다 우선순위가 낮음.
- 성능 문제도 심각하고, 보안 문제도 있음
- 아 그냥 쓰지 말라면 쓰지 마
아이템 9. try-finally보다는 try-with-resources를 사용하라
'스터디 > 이펙티브 자바 스터디' 카테고리의 다른 글
7장 : 람다와 스트림 (0) | 2023.04.06 |
---|---|
6장 : 열거 타입과 애너테이션 (0) | 2023.04.06 |
5장 : 제네릭 (0) | 2023.04.06 |
4장 : 클래스와 인터페이스 (0) | 2023.04.06 |
3장 : 모든 객체의 공통 메서드 (0) | 2023.04.05 |