본문 바로가기

책/Effective Java

객체 생성과 파괴

생성자 대신 정적 팩토리 메서드를 고려하라

장점 

 - 이름을 가질 수 있다.

 - 호출될 때 마다 인스턴스를 새로 생성하지 않아도 된다.

 - 반환 타입의 하위 타입 객체를 반환할 수 있다.

 - 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

 - 정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

단점

 - 상속을 하려면 public이나 protected 생성자가 필요하니 정적 팩토리 메서드만 제공하면 하위 클래스를 만들 수 없다.

 - 사용자가 찾기가 어렵다.


생성자에 매개변수가 많다면 빌더를 고려하라

점층적 생성자 패턴 

 - 매개변수 개수가 많아지면 코드를 작성하거나 읽기 어렵다.

자바빈즈 패턴(setter method 사용)

 - 객체 하나를 만들려면 메서드를 여러 개 호출해야 하고, 객체가 완전히 생성되기 전까지는 일관성이 무너진 상태에 놓이게 된다.

 - 클래스를 불변으로 만들 수 없다.

빌더 패턴

 - 명명된 선택적 매개변수를 흉내 낸 것

 - 계층적으로 설계된 클래스와 함께 쓰기에 좋다.


private 생성자나 열거 타입으로 싱글턴임을 보증하라

 - 클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있다.

public static final 필드 방식

 - 해당 클래스가 싱글턴임이 API에 명백히 드러난다.

 - 간결하다.

정적 팩토리 메서드 방식

 - API를 바꾸지 않고도 싱글턴이 아니게 변경할 수 있다.

 - 정적 팩토리를 제네릭 싱글턴 팩토리로 만들 수 있다.

 - 정적 팩토리 메서드 참조를 공급자(supplier)로 사용할 수 있다.

원소가 하나인 enum type을 사용 - Best

 - public static final 필드 방식과 비슷하지만, 더 간결하다.

 - 추가 노력 없이 직렬화 할 수 있다.

 - 아주 복잡한 직렬화 상황이나 리플렉션 공격에서도 제2의 인스턴스가 생기는 일을 완벽히 막아준다.


인스턴스화를 막으려거든 private 생성자를 사용하라

 - 추상 클래스롤 만드는 것으로는 인스턴스화를 막을 수 없다.

 - private 생성자를 추가하면 상속도 불가능하게 하는 효과도 있다.


자원을 직접 명시하지 말고 의존 객체 주입을 사용하라

 - 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.

 - 인스턴스를 생성할 때 생성자에 필요한 자원을 넘겨주는 방식이 좋다.

 - 의존 객체 주입을 사용하면 클래스의 유연성, 재사용성, 테스트 용이성을 엄청나게 개선해준다.


불필요한 객체 생성을 피하라

 - String str = new String("xxx"); (X) : String str = "xxx"; (O)

 - Boolean(String) (X) : Boolean.valueOf(String) (O)

 - 안 좋은 예

String s = "......"; 

s.matches("......");

 - 좋은 예

private Static final Pattern ROMAN = Pattern.compile("......"); 

String s = "......"; 

ROMAN.matcher(s).matches();

 - 박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의 하자.


다 쓴 객체 참조를 해제하라

 - 객체 참조를 null 처리하는 일은 예외적인 경우여야 한다. 다 쓴 참조를 해제하는 가장 좋은 방법은 그 참조를 담은 변수를 유효 범위 밖으로 밀어내는 것이다.

 - 자기 메모리를 직접 관리하는 클래스라면 항상 메모리 누수에 주의해야 한다.

 - 캐시도 메모리 누수를 일으키는 주범이다.


finalizer와 cleaner 사용을 피하라

 - finalizer는 예측할 수 없고, 상황에 따라 위험할 수 있어 일반적으로는 불필요하다.

 - cleaner는 finallizer보다는 덜 위험하지만, 예측할 수 없고, 느리고, 일반적으로는 불필요하다.

 - finalizer와 cleaner로는 즉시 수행된다는 보장이 없다. 즉, 제때 실행되어야 하는 작업은 절대 할 수 없다.

 - 상태를 영구적으로 수정하는 작업에서는 절대 ffinalizer나 cleaner에 의존해서는 안된다.

 - finalizer와 cleaner는 심각한 성능 문제를 동반한다.

 - finalizer를 사용한 클래스는 finalizer 공격에 노출되어 심각한 보안 문제를 일으킬 수도 있다.


try-finally 보다는 try-with-resource를 사용하라

 - 코드는 더 짧고, 분명해지고, 만들어지는 예외 정보도 훨씬 유용하다.


' > Effective Java' 카테고리의 다른 글

람다와 스트림  (0) 2020.03.20
열거 타입과 애너테이션  (0) 2020.03.18
제네릭  (0) 2020.03.17
클래스와 인터페이스  (0) 2020.03.14
모든 객체의 공통 메서드  (0) 2020.03.13