effective java 2장 객체 생성과 파괴

bluesky·2023년 11월 14일

학습 방식.

  • 일단 떠오르는 걸 적기.
  • 내용 중에서 핵심을 1문장씩 정리.(내용을 다 옮겨 적지 말것. 키워드 위주. 키워드만 표시 해도 무난. 세상엔 많은 블로그 자료가 있음.
  • 오히려 밑줄 친것들 의문 들었던 것들을 집중 파헤치기.

아이템 1. 생성자 대신 정적 팩터리 메서드를 고려하라

  • 생성자는 그 의미를 제대로 담아 내기 어려움
  • 장점
    • 따라서, 정적 팩터리 메서드는 나만의 이름으로 객체를 생성하는 규칙을 만들수 있는 장점(의미있는 메서드명). 그리고 반환타입도 다양하게 조치가 가능한 장점.
    • 매번 인스턴스 생성할 필요 없
    • 입력된 값에 따라 매번 다른 클래스
  • 단점 이해 안되는 것
    • 첫번째 상속을 하려면 퍼블릭, 프로택티드 생성자 필요하니, 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.
      • 테스트 해보니, 생성자는 선언 안하면 무조건 생성자 1개가 있고, 정적 팩터리만 제공하고, 해당 클래스를 익스탠드하는 클래스를 만들었는데 따로 컴파일 오류는 없는데, 이게 도대체 무슨 이야기인가.
    • 프로그래머가 찾기 어렵다.
      • of 와 같은 관습 필요.

아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라

  • 생성자에 매개변수가 4개이상이 되면, 빌더를 고려할것.
    • 실제로 내 경험으로도 4개 넘어갔을때, 파라미터 위치를 헷갈려 이상한 값이 들어간적이 있음.
    • 단순히 setter로 값을 세팅한다면 불변 클래스를 만들기 어렵다.
  • lombok의 builder
    • allArgsConstruct와 같이 사용하는 것은 피해야함.
      • 모든 값 설정 가능.
      • 따라서 생성자 레벨에서 “@Builder”를 쓰는것을 추천.
  • build 매서드가 호출하는 생성자에서 불변식을 검사하자. 또한 생성자에서도 검사하자 라는 내용
    • lombok의 기본 빌더는 이런 내용을 이해하지 못한다.
    • 따라서 이런것들을 해결하기 위해서, 생성자에 빌더를 걸고, 생성자 내부에서 값을 해결하는 방식도 괜찮고, builder를 직접 만들고, 각 메서드마다 직접 검사하는 방식도 좋을듯.(중간단계에서도 유효성 체크가 가능해짐.)
  • 주의
    • 성능에 민감한 상황에서 문제 될수 있음
      • 생각해보면 호출하는 메서드 개수가 많긴함.
    • 4개 이상일 때 바람직

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

  • 가끔씩 내부 데이터를 보존하지 않는 객체는 싱글턴으로 하는 것이 메모리 측면에서 좋음.
    • 딱하나만 만들어서 관리하자.
    • 그 방법으로 프라이빗 생성자로 만들면 좋음.
  • 방법
    • 1 프라이븟 매서드
    • 2 public static 메서드로
      • 장점
        • 마음이 바뀌면 싱글턴 아니게 변경 가능
        • 이해안되는 장점 - >정적 패터리를 제네릭 싱글턴 팩터리로 만들수 있다. → 아이템 30까지 기다리자.
        • 메서드 참조를 공급자로 가능.
    • 3 enum 타입의 싱글턴
      • 어색한 방법.
      • 대부분의 상황에서 좋다고함.
      • 그런데 이짓을 해본적이 살면서 없음.

아이템 4. 인스턴스화를 막으려거든 private 생성자를 사용하라

  • 이것도 이어진다. private 생성자를 만들면 외부에서 인스턴스화 할수 없기에 이 방법을 말한것.
  • 상속을 막는 효과가 있다고 함.
    • 묵시적 생성자 호출 해야하는데 없으니까.

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

  • 이것은 전략 패턴과 이어지는 내용인듯.
  • 그 자원이 그때 그때 변경 되는 것이라면, 그 자원들의 상위 타입을 내부에 변수로 넣고, 의존 객체 주입으로 관리하라는 의미인듯.
  • 사용하는 자원에 따라 동작이 달라지는 클래스에는 정적 유틸리티 클래스나 싱글턴 방식이 적합하지 않다.
  • 예시코드.
  • 장점
    • 유연한 코드 작성이 가능해짐.
  • 단점
    • 코드를 어지럽게 만듦.
    • ← 의존 객체 프레임 워크를 사용하여 보완하자(Spring)
  • 어떤 상황에서 이걸 써야할까?가 중요할듯.

아이템 6. 불필요한 객체 생성을 피하라

  • 생서자 대신 팩터리 메서드를 씀으로써 불필요한 객체 생성을 피할수 있다.
    • 그 메서드 내에서 관련된 처리를 함.
  • 유의사항
    • String matches는 성능에 유의하여 사용
    • 오토 박싱 주의
      • ex)

        Long sum;
        sum +=1; 이것을 반복.
      • 박싱된 타입의 인스턴스 생성이 일어나서 느림. 메모리도 차지.

  • 방어적 복사에 실패하면 언제 터질지 모르는 버그 ← 아이템 50. 확인해둘것.
    하지만, 불필요한 객체 생성능 형태와 성능에만 영향

아이템 7. 다 쓴 객체 참조를 해제하라

  • 다 쓴 객체 참조가 있을 것이다.
    • 그 예로 스택을 이야기했던 것이 기억남.
    • 스택과 같이 배열로 관리하면, 다쓴 객체인지 알길이 없음.
      • 방법으로 수동으로 안쓰는 객체는 null로 치환해둘것.(ex 주소를 같는 배열의 값을 Null 로 설정)
  • 자기 메모리를 직접관리하는 클래스는 메모리 누수에 주의하자.

운 좋게 캐시 외부에서 키(key)를참조하는 동안만(값이 아니다) 엔트리가 살아 있는 캐시가 필요한 상황이라면 WeakHashMap 을 사용해 캐시를 만들자. 다 쓴 엔트리는 그 즉시 자동으로 제거될 것이다. 단, WeakHashMap 은 이러한 상황에서만 유용하다는 사실을 기억하자

이펙티브 자바 Effective Java 3/E | 조슈아 블로크 저/개앞맵시(이복연) 역

[크레마 예스24 eBook]
http://m.yes24.com/Goods/Detail/90870798

  • 누수의 3번째 주범 리스너랑 콜백
    • 대처 : 콜백을 약한 참조(weekhashmap)로 저장하면 gc가 즉시 수거.
    • 이해 못함.

https://blue-mina.tistory.com/4

  • 참조에 대해
    • 강한 : 일반적 방식. GC의 대상이 아님. Integer prime = 1;
    • 부드러운 : SoftRefernce이용. 메모리부족 아니면 gc안함.
    • 약한: WeekReference이용.
      • WeakReference soft = new WeakReference(prime);
      • prime이 널이면, GC
  • WeekHashMap
    • WeekReference의 특징이 사용됨.
    • key에 해당하는 객체가 null이면 gc의 대상이 됨.(즉, key가 메모리에서 제거된다 라고 볼수 있을듯)

https://bepoz-study-diary.tistory.com/340

https://blog.breakingthat.com/2018/08/26/java-collection-map-weakhashmap/

https://medium.com/hackernoon/using-weahhashmap-to-save-references-to-callbacks-ed4f78ccb33

아이템 8. finalizer와 cleaner 사용을 피하라

  • 써본적이 없어서 와닿지 않았다.
  • 2가지 객체 소멸자.
  • 예측할수 없고, 느리고, 불필요하다고함. gc에 의해 언제 소멸될지를 모름.
  • 대안은?
    • AutoClosable을 구현, 인스턴스 다쓰면 close 매서드를 호출할것.

아이템 9. try-finally보다는 try-with-resources를 사용하라

  • 이거 쓰는것이 사용자의 실수를 막는 효과도 있고, 2중으로 try-catch를 하는 번거로움도 피하게 된다.
  • 이거 쓰려면 AutoClosable을 구현 했어야함.
static String firstLineOfFile(String path, String defaultVal) {
        try (BufferedReader br = new BufferedReader(
                new FileReader(path))) {
            return br.readLine();
        } catch (IOException e) {
            return defaultVal;
        }
    }
profile
SMART https://github.com/dongseoki?tab=repositories

0개의 댓글