Java中列表List的可变性和不变性

以下Java代码示例List分可变的,不可变的两种:

1、可变
ArrayList 是 List 的可变实现

@Test
public void arrayList()
{
    // Mutable
    List<String> list = new ArrayList<>();
    list.add(
"✅"); // Works
    
    Assertions.assertEquals(List.of(
"✅"), list);
}

LinkedList 是 List 的可变实现

@Test
public void linkedList()
{
    // Mutable
    List<String> list = new LinkedList<>();
    list.add(
"✅"); // Works

    Assertions.assertEquals(List.of(
"✅"), list);
}

CopyOnWriteArrayList 是 List 的可变和线程安全实现。

@Test
public void copyOnWriteArrayList()
{
    // Mutable
    List<String> list = new CopyOnWriteArrayList<>();
    list.add(
"✅"); // Works

    Assertions.assertEquals(List.of(
"✅"), list);
}

Arrays.asList()返回一个可变但不可增长的 List 实现。
这意味着您可以将 List 中的元素设置为不同的值,但不能添加或删除 List 中的元素。List 的这种实现类似于 Java 数组。

@Test
public void arraysAsList()
{
    // Mutable but not growable
    List<String> list = Arrays.asList(
"✅");
    list.set(0,
"✔️"); // Works

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(0,
"⛔️"));
    Assertions.assertEquals(List.of(
"✔️"), list);
}


Collections.synchronizedList 返回一个 "有条件线程安全 "的 List 实例。
所谓 "有条件线程安全",是指像 iterator、stream 和 parallelStream 这样的方法是不安全的,开发者必须使用显式锁对其进行保护。

@Test
public void collectionsSynchronizedList()
{
    // Mutable
    List<String> arrayList = new ArrayList<>();
    arrayList.add(
"✅");

    
// Mutable and "Conditionally Thread-safe"
    List<String> list = Collections.synchronizedList(arrayList);

    Assertions.assertEquals(List.of(
"✅"), list);
    list.add(
"✅");
    Assertions.assertEquals(List.of(
"✅", "✅"), list);
}


Stream.collect(Collectors.toList()) 将返回一个可变的 List。

@Test
public void streamCollectCollectorsToList()
{
    // Mutable
    List<String> list = Stream.of(
"✅")
            .collect(Collectors.toList());
    list.add(
"✅");

    Assertions.assertEquals(List.of(
"✅", "✅"), list);
}

2、不可变
Collections.emptyList() 返回不可变的空 List。

@Test
public void collectionsEmptyList()
{
    // Immutable
    List<String> list = Collections.emptyList();

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(0,
"⛔️"));
    Assertions.assertEquals(List.of(), list);
}

Collections.singletonList() 返回不可变的单例 List。

@Test
public void collectionsSingletonList()
{
    // Immutable
    List<String> list =
            Collections.singletonList(
"✅");

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(
"⛔️"));
    Assertions.assertEquals(List.of(
"✅"), list);
}

Collections.unmodifiableList() 返回 List 的 "不可修改视图",
但正如下面的代码所示,它所封装的 List 可以单独修改。它所封装的 List 可以是可变的,也可以是不可变的,但如果是不可变的,视图就是多余的了。

@Test
public void collectionsUnmodifiableList()
{
    // Mutable
    List<String> arrayList = new ArrayList<>();
    arrayList.add(
"✅");

   
// "Unmodifiable" but arrayList is still Mutable
    List<String> list = Collections.unmodifiableList(arrayList);

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(
"⛔️"));
    Assertions.assertEquals(List.of(
"✅"), list);
    arrayList.add(
"⛔️");
    Assertions.assertEquals(List.of(
"✅", "⛔️"), list);
}

List.of() 返回不可变的 List。

@Test
public void listOf()
{
    // Immutable
    List<String> list = List.of(
"✅");

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(
"⛔️"));
    Assertions.assertEquals(List.of(
"✅"), list);
}

List.copyOf() 复制另一个 List 的内容,并返回一个不可变的 List。

@Test
public void listCopyOf()
{
    // Immutable
    List<String> list = List.copyOf(new ArrayList<>(List.of(
"✅")));

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(
"⛔️"));
    Assertions.assertEquals(List.of(
"✅"), list);
}

Stream.toList() 返回不可变的 List。

@Test
public void streamToList()
{
    // Immutable
    List<String> list = Stream.of(
"✅").toList();
    
    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(
"⛔️"));
    Assertions.assertEquals(List.of(
"✅"), list);
}

Stream.collect(Collectors.toUnmodifiableList()) 将返回一个不可修改的 List
它实际上是不可变的,因为没有人能轻易获得它所封装的可变 List 的指针。

@Test
public void streamCollectCollectorsToUnmodifiableList()
{
    // Mutable
    List<String> list = Stream.of(
"✅")
            .collect(Collectors.toUnmodifiableList());

    Assertions.assertThrows(
            UnsupportedOperationException.class,
            () -> list.add(
"⛔️"));
    Assertions.assertEquals(List.of(
"✅"), list);
}

​​​​​​​