카테고리 없음

자바 공부#2_06. Immutable 컬렉션?

코딩연습중 2025. 4. 6. 16:22

Immutable 객체(불변 객체)?

불변 객체는 이름 그대로, 한번 생성되면 그 내부 값을 변경할 수 없는 객체를 의미한다. 

 

불변 객체의 장점

  1. 쓰레드에 안전하여 멀티 쓰레드 환경에서 동기화를 고려하지 않아도 된다.
  2. 불변 객체는 어떤 스레드도 다른 스레드에게 영향을 줄 수 없으므로 안심하고 공유할 수 있다.
  3. 불변객체를 필드로 사용할 때 방어적 복사 (defensive-copy) 가 필요없다.
  4. 불변객체는 내부상태가 변경되지 않으므로, Map Key 와 Set 요소로 사용하기에 적합하다.
  5. 불변객체를 한번 메모리에 할당하게 되면 같은 객체를 계속 호출하여도, 새롭게 할당하지 않아도 되므로 GC의 성능을 높일 수 있다.

불변 객체 생성 전략

  1. setter 메소드를 사용하지 마라
  2. 모든 필드를 final 과 private를 사용해서 선언해라
  3. 클래스를 final 로 선언하여 Overriding을 막아라
  4. 객체를 생성하기 위한 생성자 혹은 정적 팩토리 메소드를 추가해라
  5. 인스턴스 필드에 가변객체가 포함된다면 방어적 복사를 이용하여 전달해라


이렇게 불변 객체에 대해서 어느 정도 이해했으면, 불변 컬렉션으로 넘어가겠다.

Immutable Collection

불변 컬렉션(Immutable Collection)은 컬렉션의 불변성을 보장하며 element를 추가/삭제할 수 없다.
단, 불변성은 컬렉션에만 해당하며 element의 참조나 내부 값은 변경할 수 있다.

import java.util.*;

class Person { ... }

public class Example {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Alice"));
        people.add(new Person("Bob"));

        // 불변 컬렉션 생성
        List<Person> immutablePeople = Collections.unmodifiableList(people);

        // 요소 추가/삭제 시도 → 예외 발생
        // immutablePeople.add(new Person("Charlie")); // ❌ UnsupportedOperationException

        // 요소 내부 값 변경 → 가능
        immutablePeople.get(0).changeName("Eve"); // ✅ 가능

        System.out.println(immutablePeople); // [Eve, Bob]
    }
}

 

완전한 불변을 원한다면 요소 자체(위의 경우에서는 Person)도 immutable 객체로 만들어야 함.

(참고: https://dev-cool.tistory.com/23)

 

 

불변 컬렉션 생성(Set을 예시로)

불변 컬렉션을 생성하는 데에는 보통 Collections.unmodifiableSet(), Set.of() 두 가지 방법을 사용한다.

Java 9 이전: Collections.unmodifiableSet()

Java 9 ~: Set.of() 

주로 자바 버전에 따라 이렇게 쓰는 것 같다.

 

1. unmodifiableSet()

unmodifiableSet() 을 사용해 Immutable Collection을 만들기 위한 코드는 다음과 같다.

Set<String> set = new HastSet<>();
// ... add some elements in set
set = Collections.unmodifiableSet(set);

 

2. Set.of()

Set.of() 을 사용해 Immutable Collection을 만들기 위한 코드는 다음과 같다.

Set<String> set = Set.of("A", "B", "C"); // 변경 불가한 리스트

 

 

 

 

Immutable 컬렉션 사용 예시

📌 1. 컨트롤러 응답에 불변 리스트 사용

@GetMapping("/tags")
public ResponseEntity<List<String>> getTags() {
    List<String> tags = tagService.findAllTags();
    return ResponseEntity.ok(List.copyOf(tags));
}

List.copyOf(...)는 외부 리스트를 방어적으로 복사해 불변 리스트로 만든다.


📌 2. 상수로 고정된 리스트 만들기

public class Constants {
    public static final List<String> REGIONS = List.of("서울", "부산", "제주");
}

📌 3. 생성자에서 불변 컬렉션 저장

public class UserDto {
    private final List<String> roles;

    public UserDto(List<String> roles) {
        this.roles = List.copyOf(roles); // 방어적 복사
    }

    public List<String> getRoles() {
        return roles;
    }
}

❗ 주의점

List.of() 최대 10개 요소까지만 Map.of() 지원 (그 이상은 Map.ofEntries() 사용)
Null 불가 List.of(null) → NullPointerException 발생
내부 데이터 수정 불가 list.add(...), set.remove(...) 등 → UnsupportedOperationException 발생

 

결론

컨트롤러 응답 반환 ✅ List.copyOf()
상수 설정 값 ✅ List.of(...), Map.of(...)
동적으로 값 추가/삭제 ❌ ArrayList, HashMap 등 mutable 컬렉션 사용
멀티스레드 환경 ✅ 데이터 공유 용도에 적합

 

 

+ 추가로 unmodifiable의 immutable 여부에 대해서는

https://velog.io/@jazz_avenue/Java-9%EC%9D%98-of%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B6%88%EB%B3%80-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%83%9D%EC%84%B1%EC%9D%98-%EC%9D%B4%EC%A0%90 

참고하기.

 

참고:

- https://bibibim.tistory.com/17

- https://velog.io/@clean01/Java-%EB%B3%80%EA%B2%BD%EC%9D%B4-%EB%B6%88%EA%B0%80%EB%8A%A5%ED%95%9C-Collection%EC%9D%84-%EB%A7%8C%EB%93%A4%EA%B8%B0-Immutable-Collection-Immutable-List

- https://roomenergy.tistory.com/11
- https://sas-study.tistory.com/413

 

더 깊게 공부하기

- https://hello-judy-world.tistory.com/209