Java/Effective Java

[Effective Java] 2장. 객체 생성과 파괴

SeungbeomKim 2024. 8. 8. 23:32

[item-1] 생성자 대신 정적 팩토리 메서드를 이용하라

 

장점

  1. 메서드 이름을 가질 수 있기에 명확한 이름으로 값을 생성할 수 있습니다.
  2. 호출 때마다 인스턴스를 새로 생성하지 않을 수 있습니다.
  3. 하위 클래스를 반환하는 유연성을 얻을 수 있습니다.
  4. 매개 변수에 따라 매번 다른 클래스의 객체를 반환할 수 있습니다.
  5. 정적 팩토리 메서드를 작성하는 시점에는 해당 객체의 클래스가 존재하지 않아도 됩니다.

단점

  1. 하위 클래스로 상속하기 위해서는 public, protected 생성자가 필요합니다.
  2. 프로그래머가 찾기 어렵습니다.

 

[item-2] 생성자의 매개변수가 많다면 빌더를 고려하라

  • 생성자에 매개변수가 많아지면 코드를 직관적으로 이해하기 어렵습니다. 이에 대한 대안으로 Setter를 사용하면 여러 개의 Setter가 호출되며 객체의 생성 전까지 일관성이 무너지게 됩니다.
  • 객체의 가독성과 안정성을 높이기 위해 빌더 패턴을 고려하는 것이 좋습니다.

 

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

  • 정적 메서드나 정적 필드만을 갖는 클래스를 생성하는 경우가 있습니다. 객체 지향적인 관점에서는 좋지 않은 방식입니다.
  • 방식: public static, 정적 팩토리 메서드 활용, 원소가 하나인 열거 타입 선언

 

[item-4] 인스턴스화를 막으려거든 private 생성자를 사용하라

  • util 클래스는 인스턴스를 생성하기 위해 만든 것이 아니기에 private 생성자를 만들어줘야 합니다.
  • ex) Collections

 

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

  • 유틸리티 클래스, 싱글턴 클래스는 상태를 가지면 멀티스레딩 환경에서 버그를 불러일으킬 수 있고, 테스트하기가 어렵습니다.
  • 의존성 주입은 테스트가 용이하며 유연한 객체를 만들어 줄 뿐만 아니라, 불변성을 지킬 수 있도록 도와줍니다.
  • 여러 객체가 불변한 동일 객체에 대한 참조를 공유할 수도 있습니다.

 

[item-6] 불필요한 객체 생성을 피해라

  • 불변객체로 다루어져서 동일한 인스턴스를 또 생성할 필요가 없는 경우가 있습니다. 예를들어 String 타입은 잡자에서 특별하게 다루어져서 개발자가 의도하지 않는 이상 동일한 문자열에 대해 같은 인스턴스가 활용됩니다.
String s = new String("String"); // 새로운 객체가 생성된다
String s = "String"; // 동일한 객체가 생성된다

 

  • 생성이 불필요한 객체
    • 불변 객체, 혹은 상태가 변하지 않을 것임을 분명한 가변 객체
    • 생성 비용이 커서 캐싱의 이점을 누릴 수 있는 객체
    • 어댑터 패턴에서 사용하는 어댑터
  • 불필요한 객체 생성은 성능에 영향을 줄 수 있습니다. (객체 생성 비용이 매우 비싼 경우도 존재)
    • ex) 정규표현식 검사 객체, 오토박싱

 

[item-7] 다 쓴 객체 참조를 해제하라

  • Java는 GC에 의해 참조하지 않는 객체를 수거해 갑니다.
  • 하지만, 이 참조가 해제되지 않으면 GC가 메모리를 수거대상이라 인식하지 못하고 사용되지 않는 메모리에 의해 프로그램 성능이 망가집니다.
  • 메모리 누수 발생상황
    • 자기 메모리를 직접 관리하는 클래스, 캐시, 리스너, 콜백

 

[item-8] finalizer와 cleaner 사용을 피하라

  • 자바는 finalizer의 수행 시점은 물론, 수행 여부조차 보장해주지 않습니다.
  • try-with-resources 문에 비해 심각한 성능 저하가 있습니다.
  • finalizer attack에 노출됩니다.
  • 불가피한 영역
    • 클라이언트가 close 메서드를 호출하지 않을 경우 (FileInputStream, FileOutputStream, ThreadPoolExecutor는 안전망 역할의 finalizer를 제공하는 라이브러리)

 

[item-9] try-finally보다는 try-with-resources를 사용하라

  • 자바의 InputStream, OutputSream, Connection 과 같은 객체는 close() 메서드에 의해 닫아주어야 하는 대표적인 객체입니다.
  • 외부 자원과 연동되어 있기에 닫아주지 않으면 예외가 발생합니다.