Java

Effective Java 제 2장 - 객체 생성과 파괴

iksadnorth 2023. 8. 22. 23:02

해당 게시물은 책 'Effective Java'를 참고하고 작성했습니다.

생성자보다 정적 팩토리 메서드!
오버로딩으로 다양하게 표현한다해도 각 생성자의 구체적인 내용을 알기 어렵다.
정적 팩토리 메서드를 통해 인스턴스 생성 메서드를 구성하면
다양한 타입, 다양한 매개변수에 대응할 수 있고 구체적인 설명을 메서드명으로 보여줄 수 있다.

// 지양
Data d = new Date(instant);

// 지향
Date d = Data.from(instant);

매개변수가 많으면 Builder 패턴!
대부분의 칼럼은 기본값을 가지지만 소수의 칼럼만 설정해야 할 필요성이 있다면 빌더를 사용해야 한다.
왜냐면 모든 칼럼을 정의하는 생성자는 불필요하고
그렇다고 하여 오버 로딩을 이용해 각 경우의 수마다 생성자를 만들어 내는 것 또한 비현실적이다.

따라서 해당 경우의 경우, 빌더 패턴을 이용해 원하는 칼럼만 설정함과 동시에 모든 경우의 수에 대처할 수 있다.

Setter를 이용하면 동일한 효과를 볼 수 있으나 그 경우 칼럼의 final 제한 조건을 부여할 수 없어서 동시성에 취약하다.

더보기
public class Student {
    private int id;
    private String firstName;
    private String lastName;
    private int age;
    private String gender;
    private String address;
    private String phoneNumber;
    private String email;
    private double gpa;
    private boolean isEnrolled;

    // 모든 칼럼을 설정하는 생성자.
    public Student(int id, String firstName, String lastName, int age, String gender,
                   String address, String phoneNumber, String email, double gpa, boolean isEnrolled) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        this.address = address;
        this.phoneNumber = phoneNumber;
        this.email = email;
        this.gpa = gpa;
        this.isEnrolled = isEnrolled;
    }
    
    // 각 경우의 칼럼을 설정하는 생성자 오버로딩.
    public Student(int id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
    }
    public Student(int id, String firstName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    ...
}

특정 클래스의 인스턴스화를 막기 위해선 private 생성자를 생성!
말 그대로 유틸러티 클래스와 같이 메서드만 사용할 뿐 객체를 사용하면 안되는
클래스의 인스턴스화를 막기 위해선 생성자를 만들지 않는 것만으론 부족하다.
생성자를 안 만들면 기본 생성자를 컴파일러가 자동으로 만들기 때문에 private 생성자를 만들어야 한다. 

클래스 내 자원으로 인해 메서드 동작이 변형된다면 해당 자원을 소스 작성 시,
결정하는 것이 아니라 객체 생성 당시에 부여!
그냥 Bean Injection의 근간이 되는 개념이라고 보면 된다. 테스트의 용이성, 향상된 유지보수성을 위해
소스 코드에 의존 객체를 명시하는 것이 아니라 생성자의 파라미터로 전달하는 것이 유리하다.

Java라고 해서 메모리 누수에 강한 것은 아니다. 특수한 몇몇 경우엔 꼭 Null 처리를 해 메모리를 비워라!
다음은 직접 메모리 관리를 해야 하는 경우다.
1. Stack 클래스와 같이 클래스가 직접 관리하는 메모리는 null 처리하지 않으면 계속 불필요한 메모리가 쌓인다.
2. 캐시를 담당하는 클래스의 내부 요소들도 직접 처리를 해야 불필요한 메모리를 없앨 수 있다.
3. 리스너, 콜백의 등록을 하고 모두 사용하면 꼭 해제해줘야 한다. 그렇지 않으면 계속 쌓이기 때문이다.

finalizer, cleaner의 사용을 피해라!
해당 메서드들은 객체 파괴 시, 작동하는 메서드로서 주로 메모리 회수 및 비메모리 자원 회수에 사용된다.
하지만 Java에서는 해당 객체 회수의 타이밍을 제대로 제어할 수 없어서 사용을 지양해야 한다.

try - finall 말고 try - with - resources를 사용해라!
자원을 한 개만 사용한다면 상관없지만 자원이 많아지면 try - finall은 가독성도 떨어지고
Human Error를 유발할 가능성이 크다. try - with - resources를 이용해서 해당 위험을 제거할 수 있다.

 

'Java' 카테고리의 다른 글

Effective Java 제 4장 - 클래스와 인터페이스  (0) 2023.08.22
Effective Java 제 3장 - 모든 객체의 공통 메서드  (0) 2023.08.22
Effective Java - 1회독 요약  (0) 2023.08.15
Effective Java - 책 읽기 전략  (0) 2023.08.15
JUnit  (0) 2023.07.30