1. 概述

在Java中,不可变对象确保了线程安全并防止了意外修改,促进了健壮和可靠的代码。然而,有时我们希望向不可变列表添加元素。

在这个快速教程中,我们将探讨如何在Java中实现这一目标。

2. 问题介绍

不可变列表不允许我们向其中添加元素。但在某些情况下,我们希望在不破坏其不可变性的情况下将额外的元素合并到不可变列表中。换句话说,我们想要一个包含给定不可变列表所有元素以及新元素的不可变列表。

接下来,我们将创建一个方法来实现这一点。为了简化,我们将使用单元测试断言来验证我们的解决方案是否产生预期结果。

3. 利用可变列表

解决这个问题的一个思路是利用可变列表,如*ArrayList*。现在,让我们详细说明这个想法:

  • 创建一个ArrayList,存储原始不可变列表的所有元素
  • 将新元素添加到ArrayList
  • ArrayList转换为不可变

现在,让我们在方法中实现逻辑:

static <T> List<T> appendAnElement(List<T> immutableList, T element) {
    List<T> tmpList = new ArrayList<>(immutableList);
    tmpList.add(element);
    return Collections.unmodifiableList(tmpList);
}

正如代码所示,**appendAnElement()是一个泛型方法。**它首先创建了一个包含给定immutableList元素的ArrayList tmpList。然后,它添加elementtmpList。最后,调用Collections.unmodifiableList(tmpList)作为结果返回。如方法名称所示,**Collections.unmodifiableList()返回指定列表的只读视图。

接下来,让我们测试这个方法。由于**AssertJ可以快速检查集合是否为不可变的*,我们将使用此库来验证我们的appendAnElement()*方法是否按预期工作:

List<String> myList = List.of("A", "B", "C", "D", "E");
List<String> expected = List.of("A", "B", "C", "D", "E", "F");
List<String> result = appendAnElement(myList, "F");
assertThat(result).isEqualTo(expected)
  .isUnmodifiable();

由于**List.of()方法返回一个不可变列表*,我们使用这种方法构建了输入myList*。

如果运行测试,它会通过。所以问题得到了解决。但是,该方法只能向列表中添加一个元素。

接下来,我们将扩展方法以支持多个元素的添加。

4. 添加多个元素

Varargs(可变长度参数)允许一个方法接受同一种类型的任意数量的参数。因此,我们可以使用这种技术使我们的方法支持多个元素的添加:

@SafeVarargs
static <T> List<T> appendElements(List<T> immutableList, T... elements) {
    List<T> tmpList = new ArrayList<>(immutableList);
    tmpList.addAll(Arrays.asList(elements));
    return Collections.unmodifiableList(tmpList);
}

如上代码所示,我们使用@SafeVarargs注解方法,以确保参数化的Varargs类型是安全的,不会导致堆污染

使用这个方法,我们可以方便地向不可变列表添加单个或多个元素:

List<String> myList = List.of("A", "B", "C", "D", "E");
 
List<String> expected1 = List.of("A", "B", "C", "D", "E", "F");
List<String> result1 = appendElements(myList, "F");
assertThat(result1).isEqualTo(expected1)
  .isUnmodifiable();
 
List<String> expected2 = List.of("A", "B", "C", "D", "E", "F", "G", "H", "I");
List<String> result2 = appendElements(myList, "F", "G", "H", "I");
assertThat(result2).isEqualTo(expected2)
  .isUnmodifiable();

5. 总结

在这篇文章中,我们探讨了如何在Java中向不可变列表添加元素,并展示了如何使用Varargs使方法接受相同类型的任意数量的参数。

一如既往,示例的完整源代码可在GitHub上找到。