Java - 向不可变列表添加一个元素

Java - Add one element to an immutable list

我需要一个不可变列表,我可以从中派生第二个不可变列表,保留前一个列表的所有元素以及 Java 中的一个附加元素(没有附加库)。

Note: This question is similar to What is an efficient and elegant way to add a single element to an immutable set? but I need a list and don't have Guava.

到目前为止我尝试过的:

var list = List.of(someArrayOfInitialElements);
var newList = Stream.concat(list.stream(), Stream.of(elementToAppend))
        .collect(CollectorsCollectors.toUnmodifiableList());

这可行,但创建一个流并一个一个地复制元素对我来说似乎效率低下。鉴于 List.of() 将数据存储在基于字段或基于数组的数据结构中,您基本上可以批量复制内存。

有没有比使用流更有效的解决方案?我缺少 Java 标准库中更好的数据结构?

我会创建一个新的 ArrayList 附加元素,然后 return 作为不可修改的列表。像,

private static <T> List<T> appendOne(List<T> al, T t) {
    List<T> bl = new ArrayList<>(al);
    bl.add(t);
    return Collections.unmodifiableList(bl);
}

并对其进行测试

public static void main(String[] args) {
    List<String> al = appendOne(new ArrayList<>(), "1");
    List<String> bl = appendOne(al, "2");
    System.out.println(bl); 
}

我得到(不出所料):

[1, 2]

看到这个code run at IdeOne.com

是正确的,应该接受。进一步注意...

正在呼叫 Collections.unmodifiableList produces a collection that is a view onto the original mutable list。因此,对原始列表的修改将“渗透”到并非如此不可变的第二个列表。

此问题不适用于该答案中显示的正确代码,因为新的 ArrayList 对象故意超出范围。因此,无法访问该新列表进行修改。但在其他编码场景中,这个问题可能是一个问题。

List.copyOf

如果你想要一个独立且真正不可变的第二个列表,请使用List.copyOf in Java 10+. This returns an unmodifiable list

return List.copyOf( bl ) ;

两个答案都很好,我会创建一个更通用的解决方案:

private static <T> List<T> append(final List<T> al, final T... ts) {
    final List<T> bl = new ArrayList<>(al);
    for (final T t : ts) {
        bl.add(t);
    }
    return List.copyOf(bl);
}

它可以像以前的答案一样使用:

    List<String> al = append(new ArrayList<>(), "1");
    List<String> bl = append(al, "2");
    System.out.println(bl); 

但效率也稍微高一点:

    List<String> bl = append(new ArrayList<>(), "1", "2");
    System.out.println(bl);