Java 9 不可变集合

在软件开发领域,不变性的概念因其在创建更可预测和更健壮的代码方面的作用而受到广泛关注。不可变对象是指其状态在创建后就无法更改的对象,具有线程安全、简化调试和提高代码可维护性等优点。

Java 是使用最广泛的编程语言之一,在 Java 9 中引入了其集合框架的增强功能,以方便不可变集合的创建和使用。在本节中,我们将深入研究 Java 9 不可变集合的细节,并提供大量示例来巩固我们的理解。

什么是不可变集合?
不可变集合,顾名思义,是创建后不能修改的集合。换句话说,一旦使用其初始元素集创建了不可变集合,您就无法添加、删除或更改这些元素。任何修改集合的操作都会返回具有所需修改的新集合,而不是修改现有集合。

不可变集合的好处包括:

  • 线程安全:不可变集合可以在多个线程之间安全共享,无需同步。由于集合的状态是固定的,因此不存在并发修改问题的风险。
  • 可预测性:不变性确保对象一旦创建,其状态就保持不变,从而使代码行为更加可预测和可靠。
  • 更简单的调试:消除了与意外修改集合相关的错误,使调试更容易。
  • 函数式编程:不可变集合与函数式编程原则非常一致,使您能够编写更具表现力和简洁的代码。

Java 9 中的不可变集合
Java 9 在 java.util 包中添加了对不可变集合的支持。

  • java.util.List.of()、java.util.Set.of() 和 java.util.Map.of() 方法负责创建这些集合。这些方法分别使创建列表、集合和映射的不可变实例变得简单。
  • List、Set 和 Map 接口提供的 of() 方法提供了在 Java 9 中创建不可变集合的简洁方法。
  •  

这些方法允许您直接在方法调用中指定集合的​​元素,使代码更具可读性和表现力。

不可变集合的示例
1. 创建不可变列表:
List<String> immutableList = List.of( "苹果" ,  "香蕉" ,  "樱桃" );  

2. 创建不可变集:
Set<Integer> immutableSet = Set.of( 1 ,  2 ,  3 ,  4 ,  5 );  

3. 创建不可变映射:
Map<String, Integer> immutableMap = Map.of( "一" ,  1 ,  "二" ,  2 ,  "三" ,  3 );  

对不可变集合的操作
虽然您无法修改不可变集合,但您可以执行创建经过修改的新集合的操作。例如:

添加元素:

  1. List<String> newList =  new  ArrayList<>(immutableList);  
  2. newList.add( "葡萄" ); // 使用添加的元素创建一个新列表  

删除元素:

  1. Set<Integer> newSet =  new  HashSet<>(immutableSet);  
  2. newSet.remove( 3 ); // 创建一个新集合并删除元素  

修改map中的元素:

  1. Map<String, Integer> newMap =  new  HashMap<>(immutableMap);  
  2. newMap.put( "四" ,  4 ); // 使用添加的条目创建一个新地图  

使用多参数增强不变性
Java 9 的 of() 方法使用可变参数,允许您直接传递可变数量的参数。这简化了创建具有不同数量元素的集合的过程。

 创建不可变列表:

  1. List<String> 水果 = List.of( "苹果" ,  "香蕉" ,  "樱桃" );  
  2. List<String> 蔬菜 = List.of( "胡萝卜" ,  "西兰花" ,  "菠菜" );  
  3. List<String> mixList = List.of( "梨" ,  "番茄" ,  "卷心菜" );  

处理小型集合
不可变集合对于处理小型集合或预先知道内容的情况特别有用。它们擅长于不需要经常修改集合的场景。

限制和注意事项
虽然不可变集合提供了许多优点,但了解它们的局限性和注意事项也很重要:

  1. 内存使用:由于不可变集合会为每次修改创建新实例,因此可能会导致内存使用量增加,特别是对于大型集合。
  2. 性能:修改过程中创建新实例会影响性能,尤其是在需要频繁修改的场景下。
  3. 构建器模式:处理大量元素时,不可变集合的创建语法可能会变得很麻烦。在这种情况下,最初使用构建器模式或可变集合可能更实用。

java.util包中提供了几个支持不变性的类

java.util.Collections.unmodifiableList:

List<String> originalList = new ArrayList<>();
originalList.add("Java");
originalList.add(
"is");
originalList.add(
"immutable");

List<String> immutableList = Collections.unmodifiableList(originalList);

//如果试图修改不可变列表,将抛出 UnsupportedOperationException(不支持操作异常)。
// immutableList.add("new element"); // This line will throw an exception

java.util.Collections.unmodifiableSet:

Set<String> originalSet = new HashSet<>();
originalSet.add("Java");
originalSet.add(
"is");
originalSet.add(
"immutable");

Set<String> immutableSet = Collections.unmodifiableSet(originalSet);

// Attempting to modify the immutable set will throw UnsupportedOperationException
// immutableSet.add("new element"); // This line will throw an exception


java.util.Collections.unmodifiableMap:

Map<String, Integer> originalMap = new HashMap<>();
originalMap.put(
"one", 1);
originalMap.put(
"two", 2);
originalMap.put(
"three", 3);

Map<String, Integer> immutableMap = Collections.unmodifiableMap(originalMap);

// Attempting to modify the immutable map will throw UnsupportedOperationException
// immutableMap.put("four", 4); // This line will throw an exception

谷歌ImmutableList、ImmutableSet、 和ImmutableMap:

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMap;

ImmutableList<String> immutableList = ImmutableList.of("Java", "is", "immutable");
ImmutableSet<String> immutableSet = ImmutableSet.of(
"Java", "is", "immutable");
ImmutableMap<String, Integer> immutableMap = ImmutableMap.of(
"one", 1, "two", 2, "three", 3);