[java] 변경 불가능한 컬렉션과 수정 불가능한 컬렉션

보내는 사람 컬렉션 프레임 워크 개요 :

수정 작업을 지원하지 않는 컬렉션은 (예컨대 add, removeclear)라고도 불가능한 . 수정할 수 없는 컬렉션은 수정할 수 있습니다.

Collection객체의 변화가 보이지 않도록 추가로 보장하는 컬렉션은 불변 이라고합니다 . 변경할 수없는 컬렉션은 변경 가능 합니다.

차이를 이해할 수 없습니다. 여기서 수정 불가능불변
의 차이점은 무엇입니까 ?



답변

수정 불가능한 콜렉션은 종종 다른 코드가 여전히 액세스 할 수 있는 수정 가능한 콜렉션의 랩퍼 입니다. 그래서 당신은 당신 만 변경 불가능한 컬렉션에 대한 참조가있는 경우이를 변경할 수 없습니다, 당신은 변경하지 않는 내용에 의존 할 수 없다.

불변 수집 보장하는 것이 아무것도 더 이상 컬렉션을 변경할 수 있습니다. 수정 가능한 컬렉션을 래핑하는 경우 다른 코드가 해당 수정 가능한 컬렉션에 액세스 할 수 없도록합니다. 코드가 컬렉션에 참조를 포함하는 개체를 변경할 수는 없지만 개체 자체는 여전히 변경 가능할 수 있습니다.StringBuilder .

기본적으로 차이점은 다른 코드가 컬렉션 뒤에서 컬렉션을 변경할 수 있는지에 대한 것입니다.


답변

기본적으로 unModifiable컬렉션은 뷰이므로 간접적으로 수정 가능한 다른 참조에서 여전히 ‘수정’될 수 있습니다. 또한 읽기 전용보기로 콜렉션 로서 소스 콜렉션이 변경 될 때 수정 불가능한 콜렉션은 항상 최신 값으로 표시됩니다.

그러나 immutable콜렉션 은 다른 콜렉션 의 읽기 전용 사본 으로 취급 될 수 있으며 수정할 수 없습니다. 이 경우 소스 콜렉션이 변경되면 변경 불가능한 콜렉션은 변경 사항을 반영하지 않습니다.

다음은 이러한 차이를 시각화하는 테스트 사례입니다.

@Test
public void testList() {

    List<String> modifiableList = new ArrayList<String>();
    modifiableList.add("a");

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("--");


    //unModifiableList

    assertEquals(1, modifiableList.size());

    List<String> unModifiableList=Collections.unmodifiableList(
                                        modifiableList);

    modifiableList.add("b");

    boolean exceptionThrown=false;
    try {
        unModifiableList.add("b");
        fail("add supported for unModifiableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("unModifiableList.add() not supported");
    }
    assertTrue(exceptionThrown);

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);

    assertEquals(2, modifiableList.size());
    assertEquals(2, unModifiableList.size());
            System.out.println("--");



            //immutableList


    List<String> immutableList=Collections.unmodifiableList(
                            new ArrayList<String>(modifiableList));

    modifiableList.add("c");

    exceptionThrown=false;
    try {
        immutableList.add("c");
        fail("add supported for immutableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("immutableList.add() not supported");
    }
    assertTrue(exceptionThrown);


    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);
    System.out.println("immutableList:"+immutableList);
    System.out.println("--");

    assertEquals(3, modifiableList.size());
    assertEquals(3, unModifiableList.size());
    assertEquals(2, immutableList.size());

}

산출

modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--


답변

주요 차이점은 변경 가능한 컬렉션의 소유자가 다른 코드에 컬렉션에 대한 액세스를 제공하려고하지만 다른 코드가 컬렉션을 수정하지 못하게하는 인터페이스를 통해 액세스를 제공한다는 것입니다 (그 기능을 예약하는 동안) 소유 코드). 따라서 컬렉션은 변경할 수 없지만 특정 사용자는 컬렉션을 변경할 수 없습니다.

오라클의 Java Collection Wrapper 튜토리얼 은 다음과 같이 말합니다 (강조 추가).

수정 불가능한 랩퍼는 다음과 같이 두 가지 주요 용도로 사용됩니다.

  • 컬렉션을 만든 후에는 컬렉션을 변경할 수 없습니다. 이 경우 백업 모음에 대한 참조를 유지하지 않는 것이 좋습니다. 이것은 절대적으로 불변성을 보장합니다.
  • 특정 클라이언트가 데이터 구조에 대한 읽기 전용 액세스를 허용합니다. 백업 컬렉션에 대한 참조는 유지하지만 래퍼에 대한 참조는 제공합니다. 이러한 방식으로 클라이언트는 전체 액세스 권한을 유지하면서 보이지만 수정할 수는 없습니다 .

답변

만약 우리가 JDK Unmodifiable*와 구아바 에 대해 이야기한다면 Immutable*, 실제로 그 차이도 성능에 있습니다. 변경 불가능한 콜렉션은 일반 콜렉션 주위에 랩퍼 가 아닌 경우 더 빠르고 메모리 효율적일 수 있습니다 (JDK 구현은 랩퍼입니다).
구아바 팀 인용 :

JDK는 Collections.unmodifiableXXX 메소드를 제공하지만 우리의 의견으로는 다음과 같습니다.

<…>

  • 비효율적 : 데이터 구조에는 동시 수정 검사, 해시 테이블의 추가 공간 등을 포함하여 변경 가능한 컬렉션의 모든 오버 헤드가 여전히 있습니다.

답변

Java ™ 자습서 를 인용하려면 다음을 수행하십시오.

랩핑 된 콜렉션에 기능을 추가하는 동기화 랩퍼와 달리 수정 불가능한 랩퍼는 기능을 제거합니다. 특히 컬렉션을 수정하는 모든 작업을 가로 채서 UnsupportedOperationException을 발생시켜 컬렉션을 수정하는 기능을 제거합니다 . 수정 불가능한 랩퍼는 다음과 같이 두 가지 주요 용도로 사용됩니다.

  • 컬렉션을 만든 후에는 컬렉션을 변경할 수 없습니다. 이 경우 백업 모음에 대한 참조를 유지하지 않는 것이 좋습니다. 이것은 절대적으로 불변성을 보장합니다.

  • 특정 클라이언트가 데이터 구조에 대한 읽기 전용 액세스를 허용합니다. 백업 컬렉션에 대한 참조는 유지하지만 래퍼에 대한 참조는 제공합니다. 이러한 방식으로 클라이언트는 전체 액세스 권한을 유지하면서 보이지만 수정할 수는 없습니다.

(강조 광산)

이것은 실제로 요약합니다.


답변

위에서 언급했듯이 수정 불가능한 콜렉션은 예를 들어 수정 불가능한 콜렉션에 다른 오브젝트가 참조하고 해당 오브젝트가 변경하는 기본 대리자 콜렉션이있는 경우 수정 불가능한 콜렉션이 변경 될 수 있기 때문에 변경 불가능합니다.

불변에 관해서는 잘 정의되어 있지 않습니다. 그러나 일반적으로 개체가 “변경되지 않음”을 의미하지만 재귀 적으로 정의해야합니다. 예를 들어 인스턴스 변수가 모두 프리미티브이고 메서드에 인수가없고 프리미티브를 반환하는 클래스에 대해서는 불변을 정의 할 수 있습니다. 그런 다음 메소드는 재귀 적으로 인스턴스 변수를 변경할 수 없으며 모든 메소드가 변경 불가능하고 불변 값을 리턴하는 인수를 포함 할 수 있습니다. 메소드는 시간이 지남에 따라 동일한 값을 리턴하도록 보장되어야합니다.

우리가 그렇게 할 수 있다고 가정하면 스레드 안전 개념도 있습니다. 그리고 불변 (또는 시간이 지남에 따라 변경되지 않음)도 스레드 안전을 의미한다고 믿게 될 수 있습니다. 그러나 그것은 사실이 아닙니다이것이 다른 답변에서 아직 언급되지 않은 주요 포인트입니다. 항상 동일한 결과를 반환하지만 스레드로부터 안전하지 않은 불변 개체를 만들 수 있습니다. 이를 확인하기 위해 시간이 지남에 따라 추가 및 삭제를 유지하여 불변 콜렉션을 구성한다고 가정합니다. 이제 불변의 컬렉션은 내부 컬렉션 (시간이 지남에 따라 변경 될 수 있음)을보고 컬렉션을 만든 후 추가되거나 삭제 된 요소를 내부적으로 추가 및 삭제하여 해당 요소를 반환합니다. 컬렉션은 항상 동일한 요소를 반환하지만 분명히 값을 변경하지 않기 때문에 스레드로부터 안전하지 않습니다.

이제 우리는 불변을 스레드로부터 안전하고 절대 변경되지 않는 객체로 정의 할 수 있습니다. 일반적으로 이러한 클래스로 이어지는 불변 클래스를 작성하기위한 지침이 있지만, 예를 들어, 위의 “스냅 샷”콜렉션 예제에 설명 된대로 스레드 안전성에주의를 기울여야하는 불변 클래스를 작성하는 방법이있을 수 있습니다.


답변

Java ™ 학습서는 다음과 같이 말합니다.

랩핑 된 콜렉션에 기능을 추가하는 동기화 랩퍼와 달리 수정 불가능한 랩퍼는 기능을 제거합니다. 특히 컬렉션을 수정하는 모든 작업을 가로 채서 UnsupportedOperationException을 발생시켜 컬렉션을 수정하는 기능을 제거합니다. 수정 불가능한 랩퍼는 다음과 같이 두 가지 주요 용도로 사용됩니다.

컬렉션을 만든 후에는 컬렉션을 변경할 수 없습니다. 이 경우 백업 모음에 대한 참조를 유지하지 않는 것이 좋습니다. 이것은 절대적으로 불변성을 보장합니다.

특정 클라이언트가 데이터 구조에 대한 읽기 전용 액세스를 허용합니다. 백업 컬렉션에 대한 참조는 유지하지만 래퍼에 대한 참조는 제공합니다. 이러한 방식으로 클라이언트는 전체 액세스 권한을 유지하면서 보이지만 수정할 수는 없습니다.

차이점을 이해하기에 충분한 설명이 필요하다고 생각합니다.