[Java 응용] 자바의 불변 객체 (Immutable Object)

Kyung Jae, Cheong·2024년 8월 24일
post-thumbnail

자바의 불변 객체 (Immutable Object)

1. 불변 객체란?

  • 불변 객체(Immutable Object)는 한 번 생성된 후 그 상태를 변경할 수 없는 객체를 의미합니다.
    • 즉, 객체의 필드 값이 초기화된 이후에는 더 이상 수정될 수 없습니다.
  • 불변 객체는 여러 가지 장점이 있으며, 특히 멀티스레드 환경에서 유용하게 사용됩니다.
    • 물론 자바에서 만드는 대부분의 클래스는 값을 변경할 수 있는 가변 객체 형태로 만들어집니다.
    • 하지만 String, 래퍼, time, 등 자바가 제공하는 많은 객체들은 불변 객체로써 제공됩니다.

2. 불변 객체의 특징

  • 불변 객체의 주요 특징은 다음과 같습니다:

    1. 상태 불변성: 객체가 생성된 이후 그 상태(필드 값)가 변경되지 않습니다.
    2. Thread-Safe: 불변 객체는 상태가 변하지 않기 때문에 여러 스레드에서 동시에 접근해도 안전합니다. (스레드는 추후에 자세히 다룰 예정)
    3. 재사용 가능성: 불변 객체는 변경되지 않으므로 여러 곳에서 안전하게 재사용할 수 있습니다.

3. 불변 객체의 구현 방법

자바에서 불변 객체를 구현하는 방법은 다음과 같습니다:

  1. 모든 필드를 final로 선언: 필드가 변경되지 않도록 final 키워드를 사용하여 선언합니다.
  2. 모든 필드를 private로 선언: 외부에서 필드에 접근하여 변경할 수 없도록 private 접근 제한자를 사용합니다.
  3. 변경자 메서드 제공 금지: 필드를 변경할 수 있는 메서드(setter)를 제공하지 않습니다.
  4. 생성자에서 모든 필드를 초기화: 모든 필드를 초기화하는 생성자를 제공합니다.
  5. 객체 자체가 mutable(변경 가능)인 필드(예: 배열, 리스트 등)을 복사: 객체 내부에서 mutable한 객체를 필드로 가질 경우, 해당 객체의 방어적 복사(Defensive Copy)를 통해 불변성을 유지합니다.

3.1 불변 객체 예제

아래는 Person 클래스를 불변 객체로 구현한 예시입니다:

public final class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}
  • 위 예시에서 Person 클래스는 불변 객체로 구현되었습니다.
    • nameage 필드는 final로 선언되었으며, 클래스 외부에서 수정할 수 없습니다. 또한, 생성자를 통해서만 필드가 초기화됩니다.

3.2 복합 객체에서의 불변성 유지

  • 필드가 참조 타입(예: 배열, 리스트 등)일 경우, 방어적 복사(Defensive Copy)를 통해 불변성을 유지해야 합니다.
public final class Company {
    private final String name;
    private final List<String> employees;

    public Company(String name, List<String> employees) {
        this.name = name;
        this.employees = new ArrayList<>(employees); // 방어적 복사
    }

    public String getName() {
        return name;
    }

    public List<String> getEmployees() {
        return new ArrayList<>(employees); // 방어적 복사
    }
}
  • Company 클래스는 List<String> 타입의 employees 필드를 가지고 있습니다.
    • 불변성을 유지하기 위해, 생성자와 getter 메서드에서 employees 리스트를 복사하여 반환합니다.
  • 이렇게 하면 외부에서 리스트의 내용을 변경하더라도 원본 Company 객체의 상태는 변경되지 않습니다.

4. 불변 객체의 장단점

4-1. 장점

  • 불변 객체는 다음과 같은 여러 가지 장점을 제공합니다
    • 안전성: 불변 객체는 상태가 변경되지 않기 때문에 예상치 못한 사이드 이펙트(side effect)를 피할 수 있습니다.
    • 간결성: 불변 객체는 복잡한 상태 관리가 필요 없기 때문에 코드가 더 간결하고 이해하기 쉬워집니다.
    • 스레드 안전성: 불변 객체는 멀티스레드 환경에서 동기화(synchronization) 없이도 안전하게 사용할 수 있습니다.
    • 캐싱 및 재사용: 불변 객체는 변경되지 않으므로 여러 곳에서 안전하게 재사용하거나 캐싱할 수 있습니다.

4-2. 단점

  • 불변 객체는 몇 가지 단점도 가지고 있습니다
    • 메모리 사용량 증가: 상태가 변경될 때마다 새로운 객체를 생성해야 하므로, 메모리 사용량이 증가할 수 있습니다.
    • 성능 이슈: 특히, 대용량 데이터를 다루는 경우 불변 객체를 사용하면 성능이 저하될 수 있습니다.

5. 자바에서의 대표적인 불변 객체

  • 자바 표준 라이브러리에는 여러 불변 객체가 있습니다
    • String: 자바의 String 클래스는 불변 객체로, 문자열이 한 번 생성되면 변경할 수 없습니다.
    • Wrapper Classes: Integer, Boolean, Double 등 기본 타입의 래퍼 클래스들도 불변 객체입니다.
    • Collections: Collections.unmodifiableList(), Collections.unmodifiableMap() 등을 사용하여 불변 컬렉션을 생성할 수 있습니다.
  • 이러한 예시들은 추후 포스팅을 통해 정리할 예정입니다.

String 클래스의 불변성 예시

String s1 = "Hello";
String s2 = s1;

s1 = s1 + " World";

System.out.println(s1); // Hello World
System.out.println(s2); // Hello
  • 위 예제에서 s1이 "Hello"에서 "Hello World"로 변경되었지만, 실제로는 s1이 새로운 문자열 객체를 참조하게 된 것입니다. s2는 여전히 원래의 "Hello" 문자열을 참조하고 있음을 알 수 있습니다.

마무리

  • 불변 객체는 자바에서 중요한 개념 중 하나로, 특히 멀티스레드 환경에서 안전하고 안정적인 코드를 작성하는 데 유용합니다.
  • 불변 객체를 활용하여 보다 견고하고 유지보수하기 쉬운 코드를 작성할 수 있게 됩니다.
profile
일 때문에 포스팅은 잠시 쉬어요 ㅠ 바쁘다 바빠 모두들 화이팅! // Machine Learning (AI) Engineer & BackEnd Engineer (Entry)

0개의 댓글