Java

Effective Java 정리 #1

기기디 2023. 12. 10. 07:29

이펙티브 자바 3판 2장에 해당하는 아이템중 스스로 정리가 필요하다고 생각되는 내용들을 정리했다.

 

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

클래스의 인스턴스를 얻는 수단은 public 생성자가 있지만 그 외에 정적 팩토리 메소드를 제공하는 방법이 존재한다. 클래스의 인스턴스를 반환하는 단순한 정적 메소드를 이야기한다.

장점

  1. 정적 팩토리 메소드를 사용하는 경우 이름을 지을 수 있다.
    1. 반환될 객체의 특성을 이름에서 나타내는것이 가능하여 가독성을 높인다
    2. 자바에서 하나의 시그니쳐로는 생성자를 하나만 만들 수 있다. 임시방편으로 전달하는 파라미터의 순서를 변경하는 방법으로 이 제한을 회피할 수 있지만 좋은 방법은 아니다. 파라미터의 순서로는 각 생성자의 역할을 나타내기 충분하지 않다.
  2. 호출될때 마다 인스턴스를 새롭게 생성하지 않아도 된다.
    1. 호출시 불필요한 인스턴스 생성을 만들지 않아 생성 비용이 큰 객체의 경우 성능을 끌어올리는데 도움이 된다.
    2. 인스턴스 통제 클래스 - 정적 팩토리 방식의 클래스는 자기 자신의 인스턴스를 완전히 통제하는것이 가능하다. 인스턴스를 통제하면 클래스를 싱글톤으로 만들수도 인스턴스화 불가로 만들수도 있다. 인스턴스 통제는 플라이웨이트 패턴의 근간이 된다.
    3. 열거 타입은 인스턴스가 하나만 만들어짐을 보장한다.
  3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
    1. 반환할 객체의 클래스를 자유롭게 선택할 수 있게하는 유연성을 제공한다.
    2. 구현 클래스를 공개하지 않고 해당 객체를 반환할 수 있어 API를 작게 유지할 수 있다.
    3. 자바8을 기준으로 인터페이스도 정적메소드를 가질 수 있게 됐다.
  4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다
    1. 반환 타입의 하위 타입 범위 안에서는 어떤 클래스의 객체를 반환하든 상관 없다.
    2. 예시로 EnumSet 클래스는 public 생성자 없이 정적 팩토리만 제공한다. 원소의 길이에 따라서 64개 이하라면 Long변수 하나로 관리하는 RegularEnumSet의 인스턴스 / 65개 이상이라면 long배열로 관리하는 JumboEnumSet의 인스턴스를 반환한다.
  5. 정적 팩토리 메소드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.
    1. 이 특징은 프레임워크를 만들때의 유연함을 얻는다.
    2. 서비스 제공자 프레임워크 패턴

단점

  1. 상속을 하려면 public, protected 생성자가 필요하니 정적 팩토리 메소드만 제공하면 하위 클래스를 만들 수 없다.
    1. 해당 제약은 상속보다는 컴포지션을 사용하도록 유도하고 불변타입으로 만드려면 이 제약을 지켜야한다는 점에서 오히려 장점이 되기도 한다.
  2. 정적 팩토리 메소드는 다른 개발자가 봤을때 찾기 어렵다.

정리

  • 정적 팩토리 메소드와 public 생성자는 각각 사용할 용도가 다르니 각자의 장단점을 이해하고 사용하는게 좋다. 하지만 대부분의 경우 정적 팩토리 메소드를 쓰는게 유리한 경우가 많기 때문에 무조건 public 생성자를 제공하던 습관이 있다면 고치는게 좋다.

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

대부분의 클래스는 제대로 동작하기 위하여 하나 이상의 자원에 의존해야한다. 맞춤법 검사기라는 클래스가 있다면 사전에 의존해야하는게 예시다. 이런 클래스를 정적 유틸리티 클래스로 구현하는 경우 유연하지 않고 테스트 하기 어렵다는 단점을 가진다. 사전을 언어별로 사용할수도 있고 특수 어휘용 사전을 따로 쓸수도 있고 테스트용 사전을 쓸수도 있기 때문에 단 하나의 사전만을 가지는건 유연하지 못하다.

대신 클래스(맞춤법 검사기)가 여러 자원을 사용해야하고 클라이언트의 요구사항에 따라 사용해야하는 자원이 달라져야한다면, 인스턴스를 생성할때 생성자에 필요한 자원을 넘겨주는 방식으로 구현할 수 있다. 이 방식은 의존 객체 주입의 형태중 하나로 맞춤법 검사기를 생성할 때 의존객체인 사전을 주입해주면 된다.

이 패턴의 변형으로 생성자에 자원 팩토리를 넘겨주는 방식을 사용할 수 있다. 여기서 말하는 팩토리란 호출할때마다 특정 타입의 인스턴스를 반복해서 만들어주는 객체를 말한다. 이 변형은 팩토리 메소드 패턴 이라고도 불린다.

정리

  • 클래스가 하나 이상의 자원에 의존성을 가지고 그 자원에 따라서 클래스의 동작이 달라져야한다면 싱글턴과 정적 유틸리티 클래스를 사용하지 않는것이 좋다.
  • 자원으로 인해서 매번 새로운 클래스를 만들지 않게 하는것이 좋다. 필요한 자원을 생성자에 넘겨주자. 이 기법을 의존 객체 주입이라고도 부른다.

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

자바에서는 close메소드로 직접 닫아줘야하는 자원들이 존재한다. 놓치는 경우 성능 문제로 이어지기에 안전하게 사용하기 위하여 try-finally가 전통적으로 쓰였다. 하지만 try-finally는 자원이 둘 이상이라면 중첩구문을 유발하여 가독성이 떨어지고 특정 자원의 예외 발생시 스택 추적 내역에 다른 자원의 정보를 집어삼키는 경우도 발생한다. 이런 경우 디버깅을 어렵게 만든다.

이러한 문제들을 try-with-resorces를 통해 해결할 수 있다. 사용하기 위하여 AutoCloseable 인터페이스를 구현해야한다. tru-with-resources를 사용하며 가독성을 높일 수 있고 하나의 예외만 보여지고 숨겨지는 나머지 예외들은 콘솔창에서 suppressed를 달고 출력되어 다른 스택 내역을 덮어쓰지않고 디버깅하기 수월하다.

정리

꼭 close를 통해서 닫아줘야하는 자원을 다룰때는 try-finally말고 try-with-resources를 사용하자.

'Java' 카테고리의 다른 글

Java.lang  (0) 2024.03.05
Java Collection  (0) 2024.03.02
동기와 비동기, Java Synchronized  (0) 2022.05.28
Servlet서블릿  (0) 2022.05.25
동등성과 동일성의 차이  (0) 2022.05.25