개발자로 후회없는 삶 살기

[Java] Java의 immutable 본문

[백엔드]/[spring+JPA | 이슈해결]

[Java] Java의 immutable

몽이장쥰 2023. 7. 7. 16:02

서론

자바에서는 데이터에 변경이나 추가를 하지 못하도록 불변을 설정할 수 있는 메서드를 제공합니다. 이번 시간에는 자바의 불변에 대해 알아봅니다.

 

본론

- 복제본에 변화를 준 경우

먼저 복제본에 변화를 줄 수 있는지 없는지 살펴보겠습니다.

 

-> 배열을 입력받아 배열을 반환하는 메서드
1. Arrays.copyOf

이것은 배열을 복제하여 배열을 반환하는 메서드입니다. 복제본에 변화를 주어도 변경이 가능합니다.

 

-> 배열을 입력받아 List를 반환하는 메서드

1. List.of

변경 불가를 보장합니다.

 

2. Arrays.asList

변경은 가능하고

 

추가는 불가합니다.

 

-> List를 입력 받아 List를 반환하는 메서드

1. Collections.unmodifiableList

복제본에 변경이 불가합니다.

 

2. List.copyOf

복제본에 변경이 불가합니다.

 

- 원본의 변화

이번에는 원본에 변화를 줬을 때 참조로 인해 복제본에 변화가 가는지 살펴보겠습니다.

 

-> 배열을 입력받아 배열을 반환하는 메서드
1. Arrays.copyOf

이것은 아에 배열을 새로 만들어 원본과의 참조를 끊어 원본에 변화를 주어도 복제본에 영향이 없습니다.

 

-> 배열을 입력받아 List를 반환하는 메서드

1. List.of

원본이 변해도 복제본은 영향을 받지 않습니다.

 

2. Arrays.asList

원본이 바뀌면 복제본도 변합니다.

 

-> List를 입력 받아 List를 반환하는 메서드
1. Collections.unmodifiableList

이것은 원본과 참조하여 원본의 데이터가 변하면 복사 데이터도 변합니다.

 

2. List.copyOf

원본이 변하더라도 복제본은 변하지 않습니다.

 

변경 가능한 List 만들기 ✅

List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6))

새로운 리스트 객체를 만들어 복사하면 변경이 가능합니다. 이를 활용하는 것을 2가지 경우로 나누어 보겠습니다.

 

1. 원본은 변경 가능, 복사본을 변경 불가능

class Cars {
    private final List<Car> cars;

    public Cars(final List<Car> cars) {
        this.cars = Collections.unmodifiableList(new ArrayList<>(cars));
    }

    public int getSize() {
        return cars.size();
    }
}

한 번 감싸서 원본과 참조를 끊어서 immutable을 보장하는 방어적 복사를 할 수 있습니다. 이렇게 하면 원본에 변화가 일어나도 복사본은 변경이 일어나지 않고 복사본의 자체 수정도 불가합니다.

 

2. 원본은 변경 불가, 복사본은 변경 가능

때로는 복사 불가능한 원본에 복사본을 변경해야 할 때가 있습니다. 원본은 immutable을 보장하여 안전하게하고 복사본으로는 결과를 위한 계산을 하는 상황입니다.

 

1) 원본

public class Lotto {
    private final List<Integer> numbers;

    public Lotto(final List<Integer> numbers) {
        this.numbers = Collections.unmodifiableList(numbers);
    }

원본에 초기화를 할 때는 변경 못하게 하고

 

public List<Integer> getNumbers() {
    return new ArrayList<>(numbers);
}

반환할 때 새로운 리스트 객체를 만듭니다.

 

2) 복제본

private int getCollectCnt(List<Integer> lottoNumbers, List<Integer> answerNumbers) {
	lottoNumbers.retainAll(answerNumbers);
}

이렇게 하면 다른 곳에서 lottoNumbers에 결과를 계산하기 위한 수정을 해야할 때 원본의 불변을 보장하며 변경할 수 있습니다.

 

결론

자바의 불변에 대해 알아보면서 참조로 인해 변경도 알아보았습니다. 웹 어플리케이션에서 getter를 사용할 때 불변으로 주는 것이 관례인데 그때 적절한 메서드를 사용해서 반환해야 합니다.

Comments