天道酬勤,学无止境

关于不可变列表(由Arrays.asList()创建)(Regarding immutable List (created by Arrays.asList()))

问题

当我们使用java.util.Arrays.asList()从数组创建列表时,该列表是不可变的。 我很好奇,当List (或SetMap )的基本目的是具有动态大小并能够随意添加和删除元素时,为什么我们要创建一个不可变的列表。 当我们需要固定大小的数据结构时,我们使用数组,当我们需要动态数据结构时,我们使用ListSetMap等。那么拥有不可变列表的目的是什么? 我在做作业时遇到了这个问题。

回答1

当我们使用java.util.Arrays.asList()从数组创建列表时,该列表是可变的。

是和否:可以通过调用以下列表来修改列表

list.set(index, element);

但是该列表可能没有结构上的修改。 这意味着不可能将元素添加到列表中或从列表中删除元素。 原因很简单,因为列表仍受数组支持,并且数组的大小可能不会更改。

当我们需要固定大小的可变集合时,我们就选择数组

这就是这里的关键点:数组不是Collection。 Arrays.asList方法主要充当“数组世界”和“集合世界”之间的“桥梁”。

Arrays.asList方法允许您例如将数据传递给需要Collection的方法:

// A method that expects a collection:
void process(List<String> strings) { ... }

void call()
{
    String array[] = new String[] { "A", "B", "C" };

    // Pass the array (as a list) to the method:
    process(Arrays.asList(array));
}

该应用案例包括从数组创建其他集合。 例如,如果您有一个数组,并且想要创建一个包含数组中元素的Set ,则可以

String array[] = new String[] { "A", "B", "C" };
Set<String> set = new HashSet<String>();
for (String s : array) 
{
    set.add(s);
}

但是,使用Arrays.asList方法,可以更方便地完成此操作:

Set<String> set = new HashSet<String>(Arrays.asList(array));

可以说Arrays.asList方法是Collection#toArray方法的对应方法,它以相反的方向工作(尽管此方法通常涉及创建和填充数组,而Arrays.asList方法只是“包装”一个数组,让它看起来像“ List )。

回答2

java.util.Arrays.asList()调用return new ArrayList<>(a); 但是此ArrayList是Arrays的私有类,该类扩展了AbstractList并覆盖了某些实现。 因此,期望java.util.ArrayList的行为是不公平的。 如果查看java.util.AbstractList您会看到可以调用add(E e),但不能调用许多其他方法。 因此,按照当前的实现,您可以在列表底部添加一个元素,但不能更改列表的现有结构。

回答3

这是因为AbstractList类中的add()由Arrays java类(内部使用)下的自定义ArrayList(内部静态类)扩展了。 请注意,此add()方法与java.util.ArrayList中定义的方法不同,但与java.util.Arrays$ArrayList定义的方法不同。

数组具有固定大小的属性,由jvm本地提供。 即使Arrays.copyOf()的大小增加了也可以使用,例如Arrays.copyOf(arr, 10); //10 is the length Arrays.copyOf(arr, 10); //10 is the length ,原始数组为arr= int[]{1,2} // size is two 。 它使用System.arraycopy()创建最终调用一个本机方法

[静态void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)]

请注意,以上列表仅具有大小限制,如果您确实想使可变列表不可变,请尝试使用Collections.unmodifiableList(mutableList); 不可移植性不是jvm定义的概念,而是开发人员的想法。 请参阅https://stackoverflow.com/a/42071121/5620851和https://stackoverflow.com/a/42138471/5620851

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 一行初始化ArrayList(Initialization of an ArrayList in one line)
    问题 我想创建用于测试目的的选项列表。 首先,我这样做: ArrayList<String> places = new ArrayList<String>(); places.add("Buenos Aires"); places.add("Córdoba"); places.add("La Plata"); 然后,我将代码重构如下: ArrayList<String> places = new ArrayList<String>( Arrays.asList("Buenos Aires", "Córdoba", "La Plata")); 有一个更好的方法吗? 回答1 实际上,初始化ArrayList的“最佳”方法可能是您编写的方法,因为它不需要以任何方式创建新的List : ArrayList<String> list = new ArrayList<String>(); list.add("A"); list.add("B"); list.add("C"); 问题是引用该list实例需要大量输入。 还有其他选择,例如使用实例初始化程序(也称为“双括号初始化”)创建匿名内部类: ArrayList<String> list = new ArrayList<String>() {{ add("A"); add("B"); add("C"); }}; 但是,我不太喜欢这种方法
  • 如何用Java创建新列表(How to make a new List in Java)
    问题 我们创建一个Set为: Set myset = new HashSet() 我们如何用Java创建一个List ? 回答1 List myList = new ArrayList(); 或使用泛型(Java 7或更高版本) List<MyType> myList = new ArrayList<>(); 或带有泛型(旧的Java版本) List<MyType> myList = new ArrayList<MyType>(); 回答2 此外,如果您要创建一个包含所有内容的列表(尽管它将是固定大小的): List<String> messages = Arrays.asList("Hello", "World!", "How", "Are", "You"); 回答3 让我总结一下并添加一些内容: JDK 1. new ArrayList<String>(); 2. Arrays.asList("A", "B", "C") 番石榴 1. Lists.newArrayList("Mike", "John", "Lesly"); 2. Lists.asList("A","B", new String [] {"C", "D"}); 不可变的清单 1. Collections.unmodifiableList(new ArrayList<String>(Arrays.asList("A
  • 尝试从列表中删除元素时,为什么会出现UnsupportedOperationException?(Why do I get an UnsupportedOperationException when trying to remove an element from a List?)
    问题 我有以下代码: public static String SelectRandomFromTemplate(String template,int count) { String[] split = template.split("|"); List<String> list=Arrays.asList(split); Random r = new Random(); while( list.size() > count ) { list.remove(r.nextInt(list.size())); } return StringUtils.join(list, ", "); } 我得到这个: 06-03 15:05:29.614: ERROR/AndroidRuntime(7737): java.lang.UnsupportedOperationException 06-03 15:05:29.614: ERROR/AndroidRuntime(7737): at java.util.AbstractList.remove(AbstractList.java:645) 这怎么会是正确的方法? Java 15 回答1 您的代码有很多问题: 在Arrays.asList返回固定大小的列表 从API: Arrays.asList:返回由指定数组支持的固定大小的列表。
  • Java中的不可变数组(Immutable array in Java)
    问题 在Java中,有没有一成不变的替代原始数组的方法? 将原始数组定为final实际上并不能阻止人们做类似的事情 final int[] array = new int[] {0, 1, 2, 3}; array[0] = 42; 我希望数组的元素不可更改。 回答1 不适用于原始数组。 您将需要使用列表或其他数据结构: List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3)); 回答2 我的建议是不要使用数组或不可unmodifiableList而要使用为此目的而存在的番石榴的ImmutableList。 ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3); 回答3 正如其他人指出的那样,Java中不能有不可变的数组。 如果您绝对需要一个返回不影响原始数组的数组的方法,那么您每次都需要克隆该数组: public int[] getFooArray() { return fooArray == null ? null : fooArray.clone(); } 显然,这是相当昂贵的(因为每次调用getter都会创建一个完整副本),但是如果您不能更改界面(例如使用List ),并且不能冒险让客户更改内部结构,那么可能有必要。
  • 不变类的例子(Examples of immutable classes)
    问题 我已经知道不可变类的定义,但是我需要一些示例。 回答1 标准API中一些著名的不可变类: java.lang.String(已经提到) 基本类型的包装器类:java.lang.Integer,java.lang.Byte,java.lang.Character,java.lang.Short,java.lang.Boolean,java.lang.Long,java.lang.Double, java.lang.Float java.lang.StackTraceElement(用于构建异常stacktraces) 大多数枚举类是不可变的,但实际上这取决于具体情况。 (不要实现可变的枚举,这会在某种程度上使您搞砸。)我认为,至少标准API中的所有枚举类实际上都是不可变的。 java.math.BigInteger和java.math.BigDecimal(至少这些类本身的对象,子类可能会引入可变性,尽管这不是一个好主意) java.io.File。 请注意,这表示VM外部的对象(本地系统上的文件),该对象可能存在也可能不存在,并且具有一些方法可以修改和查询此外部对象的状态。 但是File对象本身保持不变。 (java.io中的所有其他类都是可变的。) java.awt.Font-表示用于在屏幕上绘制文本的字体(可能有一些可变的子类,但这肯定没有用) java.awt
  • Java List.add()UnsupportedOperationException(Java List.add() UnsupportedOperationException)
    问题 我尝试将对象添加到List<String>实例,但它引发UnsupportedOperationException 。 有人知道为什么吗? 我的Java代码: String[] membersArray = request.getParameterValues('members'); List<String> membersList = Arrays.asList(membersArray); for (String member : membersList) { Person person = Dao.findByName(member); List<String> seeAlso; seeAlso = person.getSeeAlso(); if (!seeAlso.contains(groupDn)){ seeAlso.add(groupDn); person.setSeeAlso(seeAlso); } } 错误信息: java.lang.UnsupportedOperationException java.util.AbstractList.add(Unknown Source) java.util.AbstractList.add(Unknown Source) javax.servlet.http.HttpServlet.service(HttpServlet
  • 如何确定数组在Java中是否包含特定值?(How do I determine whether an array contains a particular value in Java?)
    问题 我有一个String[] ,其值如下所示: public static final String[] VALUES = new String[] {"AB","BC","CD","AE"}; 给定String s ,是否存在测试VALUES是否包含s的好方法? 回答1 Arrays.asList(yourArray).contains(yourValue) 警告:这不适用于图元数组(请参见注释)。 从java-8开始,您现在可以使用Streams。 String[] values = {"AB","BC","CD","AE"}; boolean contains = Arrays.stream(values).anyMatch("s"::equals); 要检查int , double或long数组是否包含值, LongStream分别使用IntStream , DoubleStream或LongStream 。 例子 int[] a = {1,2,3,4}; boolean contains = IntStream.of(a).anyMatch(x -> x == 4); 回答2 Java SE 9的简要更新 引用数组是错误的。 对于这种情况,我们要紧紧追赶。 从Java SE 9开始,我们有了Set.of private static final Set<String>
  • 从Java 8中的java.util.stream.Stream检索列表(Retrieving a List from a java.util.stream.Stream in Java 8)
    问题 我在玩Java 8 lambda,以轻松过滤集合。 但是我没有找到一种简洁的方法来在同一条语句中以新列表的形式检索结果。 到目前为止,这是我迄今为止最简洁的方法: List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L); List<Long> targetLongList = new ArrayList<>(); sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add); 网上的示例没有回答我的问题,因为它们停止了而没有生成新的结果列表。 必须有一种更简洁的方法。 我本来希望Stream类具有toList() , toSet() ,...等方法。 有没有一种方法可以由第三行直接分配变量targetLongList ? 回答1 如果您的流保持顺序运行,那么您正在做的事情可能是最简单的方法,否则您将必须在forEach之前调用对sequence()的调用。 [稍后编辑:必须调用forEach(targetLongList::add) ()的原因是,如果流是并行的,那么按forEach(targetLongList::add)编写的代码( forEach
  • 如何通过构造初始化HashSet值?(How to initialize HashSet values by construction?)
    问题 我需要创建一个具有初始值的Set 。 Set<String> h = new HashSet<String>(); h.add("a"); h.add("b"); 有没有办法在一行代码中做到这一点? 例如,它对于最终的静态字段很有用。 回答1 我使用的速记不是很省时,但是适合单行: Set<String> h = new HashSet<>(Arrays.asList("a", "b")); 同样,这不是省时的,因为您正在构造数组,转换为列表并使用该列表创建集合。 当初始化静态最终集时,我通常这样写: public static final String[] SET_VALUES = new String[] { "a", "b" }; public static final Set<String> MY_SET = new HashSet<>(Arrays.asList(SET_VALUES)); 稍微不那么丑陋,效率对于静态初始化无关紧要。 回答2 集合文字是为Java 7排定的,但没有加入。因此还没有自动实现的功能。 您可以使用番石榴的套装: Sets.newHashSet("a", "b", "c") 或者,您可以使用以下语法,这将创建一个匿名类,但是它很hacky: Set<String> h = new HashSet<String>() {{ add("a")
  • 有效实现不可变(双)LinkedList(Efficient implementation of immutable (double) LinkedList)
    问题 看过这个问题不可变还是不可变? 在阅读了我以前关于不变性的问题的答案后,我仍然对有效实现不变的简单LinkedList感到有些困惑。 就数组而言,这似乎很容易-复制数组并基于该副本返回新结构。 假设我们有一个通用的Node类: class Node{ private Object value; private Node next; } 并且基于上述类的LinkedList允许用户添加,删除等。现在,我们如何确保不可变性? 插入元素时,是否应该将所有引用递归复制到列表中? 我也对不可变或不可变的答案感到好奇吗? 提到了通过二叉树优化的cerain优化,从而导致log(n)的时间和空间。 另外,我在某处读到,在前面加上一个elem也是0(1)。 这让我很困惑,好像我们没有提供引用的副本一样,那么实际上我们在两个不同的源中修改了相同的数据结构,这打破了不变性。 您的答案是否还会在双向链表上起作用? 我期待对任何其他问题/解决方案的任何答复/指针。 在此先感谢您的帮助。 回答1 假设我们有一个基于上述的Node类和LinkedList类,允许用户添加,删除等。现在,我们如何确保不可变性? 通过将对象的每个字段都设为只读,并确保由这些只读字段之一引用的每个对象也是不可变的对象,可以确保不变性。 如果这些字段都是只读的,并且仅引用其他不可变数据,那么显然该对象将是不可变的! 插入元素时
  • Regarding immutable List (created by Arrays.asList())
    When we create a list from an array using java.util.Arrays.asList(), the list is immutable. I am just curious to know why do we want to create a immutable list when the basic purpose of List (or Set or Map) is to have dynamic size and to be able to add, remove elements at will. When we need a fixed size data structure we go for Array and when we need a dynamic data structure we go for List or Set or Map etc. So what is the purpose of having a immutable list? I came across this while working on my assignment.
  • 如何初始化列表 Java中的对象?(How to initialize List<String> object in Java?)
    问题 I can not initialize a List as in the following code: List<String> supplierNames = new List<String>(); supplierNames.add("sup1"); supplierNames.add("sup2"); supplierNames.add("sup3"); System.out.println(supplierNames.get(1)); I face the following error: Cannot instantiate the type List<String> How can I instantiate List<String>? 回答1 如果您检查API List您会注意到它说: Interface List<E> 作为interface意味着它不能被实例化(不可能有new List() )。 如果检查该链接,则会发现一些实现List class : 所有已知的实施类: AbstractList , AbstractSequentialList , ArrayList , AttributeList , CopyOnWriteArrayList , LinkedList , RoleList , RoleUnresolvedList , Stack ,
  • 不可变与不可修改的集合(Immutable vs Unmodifiable collection)
    问题 从集合框架概述中: 不支持修改操作(例如add , remove和clear )的集合称为不可修改的。 不可修改的集合是可修改的。 额外保证不能在Collection对象中看到任何更改的Collection称为不可变的。 不变的集合是可变的。 我无法理解区别。 这里的不可修改的和不可变的有什么区别? 回答1 不可修改的集合通常是可修改集合的包装,其他代码仍可以访问该可修改集合。 所以,当你不能给它的任何变化,如果你只需要不可修改的集合的引用,你不能依靠内容不改变。 不可变的集合保证没有任何东西可以再更改集合。 如果包装可修改的集合,则确保没有其他代码可以访问该可修改的集合。 请注意,尽管没有代码可以更改集合包含引用的对象,但是对象本身仍然是可变的-创建StringBuilder的不可变集合不会以某种方式“冻结”这些对象。 基本上,区别在于其他代码是否可以更改背后的集合。 回答2 基本上unModifiable Collection是一个视图,因此可以间接从其他可修改的引用中对其进行“修改”。 同样,作为另一个集合的只读视图,当源集合发生更改时,不可修改的集合将始终显示最新值。 但是, immutable Collection可以被视为另一个Collection的只读副本,不能进行修改。 在这种情况下,当源集合更改时,不可变的集合不会反映更改 这是一个可视化此差异的测试用例。
  • 如何从ArrayList或String Array中删除所有空元素?(How to remove all null elements from a ArrayList or String Array?)
    问题 我尝试这样的循环 // ArrayList tourists for (Tourist t : tourists) { if (t != null) { t.setId(idForm); } } 但这不是很好。 谁能建议我一个更好的解决方案? 一些有用的基准可以做出更好的决策: While循环,For循环和迭代器性能测试 回答1 尝试: tourists.removeAll(Collections.singleton(null)); 阅读Java API。 该代码将为不可变列表(例如使用Arrays.asList创建)抛出java.lang.UnsupportedOperationException ; 有关更多详细信息,请参见此答案。 回答2 截至2015年,这是最好的方法(Java 8): tourists.removeIf(Objects::isNull); 注意:对于固定大小的列表(例如使用Arrays.asList创建的列表),包括不可变列表,此代码将引发java.lang.UnsupportedOperationException 。 回答3 list.removeAll(Collections.singleton(null)); 如果在Arrays.asList上使用它,它将抛出UnsupportedException ,因为它为您提供了不可变的副本
  • 为什么C#结构是不可变的?(Why are C# structs immutable?)
    问题 我只是想知道为什么结构,字符串等是不可变的? 是什么原因使它们不可变,而其余对象却可变。 使对象不可变的哪些因素被认为是什么? 为可变和不可变对象分配和释放内存的方式有何不同? 回答1 如果您对此主题感兴趣,请访问https://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/,以获取有关不可变编程的大量文章。 我只是想知道为什么结构,字符串等是不可变的? 默认情况下,结构和类不是不可变的,尽管使结构不可变是最佳做法。 我也喜欢不可变的类。 字符串是不可变的。 是什么原因使它们不可变,而其余对象却可变。 使所有类型不可变的原因: 对于不变的对象,更容易做出推理。 如果我有一个队列中包含三个项目,那么我知道它现在不为空,五分钟前它也不为空,将来也不会为空。 这是一成不变的! 一旦知道了有关事实,便可以永远使用该事实。 关于不可变对象的事实不会过时。 第一点的特殊情况:不可变对象使线程安全变得容易得多。 大多数线程安全问题是由于在一个线程上进行写入而在另一个线程上进行读取所致。 不可变对象没有写操作。 不变的对象可以拆开并重新使用。 举例来说,如果你有一个不变的二叉树,那么你可以使用它的左,右子树作为不同的树子树,而不必担心它。 在可变结构中
  • 从集合/数组/列表创建逗号分隔的字符串的最复杂的方法?(The most sophisticated way for creating comma-separated Strings from a Collection/Array/List?)
    问题 在使用数据库的过程中,我注意到我写了查询字符串,并且在此字符串中,我必须对列表/数组/集合的where子句施加一些限制。 应该看起来像这样: select * from customer where customer.id in (34, 26, ..., 2); 您可以通过将其简化为以下问题来简化此问题:您具有字符串集合,并且只想在一个字符串中创建一个以逗号分隔的字符串列表。 到目前为止,我使用的方法是这样的: String result = ""; boolean first = true; for(String string : collectionOfStrings) { if(first) { result+=string; first=false; } else { result+=","+string; } } 但这就像您看到的非常难看。 您乍看之下看不到会发生什么,尤其是当构造的字符串(如每个SQL查询)变得复杂时。 您的(更多)优雅方式是什么? 回答1 注意:这个答案在11年前写的时候是不错的,但是现在有更好的选择可以更清晰地在一行中执行此操作,无论是仅使用Java内置类还是使用实用程序库。 请参阅下面的其他答案。 由于字符串是不可变的,因此如果要在代码中更改String,则可能要使用StringBuilder类。
  • Collections.unmodifiableList和防御性副本(Collections.unmodifiableList and defensive copy)
    问题 如果我写 List<Integer> a1 = Arrays.asList(1, 2, 3); List<Integer> a2 = Collections.unmodifiableList(a1); a2是只读的,但是如果我写 a1.set(0,10); 那么a2也将被修改。 如果在API中说: 返回指定集合的​​不可修改视图。 此方法允许模块为用户提供对内部集合的“只读”访问权限。 那么,为什么如果我修改原始集合,并且目标复制的集合也被修改呢? 也许我误解了含义,如果是的话,写一份防御性副本的方式是什么? 回答1 是的,您理解正确。 这个想法是umodifiableCollection返回的对象不能直接更改,而可以通过其他方式更改(通过直接更改内部集合有效)。 只要可以访问内部列表,就可以更改“不可修改的”集合。 这就是为什么您通常构造一个不可修改的集合并确保没有任何东西可以进入内部列表的原因: Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3)); 由于从来都没有获取到一个参考List通过创建asList ,这是一个真正的不可修改的集合。 这种方法的优点是您根本不需要复制原始集合/列表,从而避免了使用内存和计算能力。
  • 如何使用Java 8流制作笛卡尔产品?(How can I make Cartesian product with Java 8 streams?)
    问题 我具有以下收集类型: Map<String, Collection<String>> map; 我想为每个Key从集合中的单个值创建map.size()唯一组合。 例如,假设地图如下所示: A, {a1, a2, a3, ..., an} B, {b1, b2, b3, ..., bn} C, {c1, c2, c3, ..., cn} 我想得到的结果将是一个List<Set<String>>结果,看起来类似于(排序并不重要,它只需要是一个由所有可能的组合组成的“完整”结果)即可: {a1, b1, c1}, {a1, b1, c2}, {a1, b1, c3}, {a1, b2, c1}, {a1, b2, c2}, {a1, b2, c3}, ... {a2, b1, c1}, {a2, b1, c2}, ... {a3, b1, c1}, {a3, b1, c2}, ... {an, bn, cn} 这基本上是一个计数问题,但是我想看看使用Java 8流是否可以解决。 回答1 您可以使用递归flatMap链解决此问题。 首先,当我们需要在映射值之间来回移动时,最好将它们复制到ArrayList (这不是深层副本,在您的情况下,它仅是3个元素的ArrayList ,因此额外的内存使用率很低)。 其次,为维护先前访问的元素的前缀,让我们创建一个不可变的辅助Prefix类:
  • 在Java中将列表转换为Set的最简单方法(Easiest way to convert a List to a Set in Java)
    问题 用Java将List转换为Set的最简单方法是什么? 回答1 Set<Foo> foo = new HashSet<Foo>(myList); 回答2 我同意sepp2k,但还有其他一些细节可能很重要: new HashSet<Foo>(myList); 将为您提供没有重复的未排序集合。 在这种情况下,将在您的对象上使用.equals()方法来识别重复项。 这是与.hashCode()方法结合完成的。 (有关平等的更多信息,请点击此处) 提供排序集的替代方法是: new TreeSet<Foo>(myList); 如果Foo实现了Comparable,则此方法有效。 如果不是,那么您可能要使用比较器: Set<Foo> lSet = new TreeSet<Foo>(someComparator); lSet.addAll(myList); 这依赖于compareTo()(来自可比较的接口)或compare()(来自比较器)以确保唯一性。 因此,如果您只关心唯一性,请使用HashSet。 如果要进行排序,请考虑使用TreeSet。 (请记住:稍后进行优化!)如果时间效率很重要,而空间效率很重要,请使用HashSet,请查看TreeSet。 请注意,可以通过Trove(和其他位置)使用Set和Map的更有效实现。 回答3 如果您使用Guava库: Set<Foo> set =
  • 如何将Java8流的元素添加到现有列表中(How to add elements of a Java8 stream into an existing List)
    问题 Collector的Javadoc显示了如何将流的元素收集到新的List中。 是否存在将结果添加到现有ArrayList中的单行代码? 回答1 注意: nosid的答案显示了如何使用forEachOrdered()添加到现有集合中。 这是对现有集合进行变异的有用且有效的技术。 我的答案解决了为什么您不应该使用Collector来突变现有收集器的原因。 简短的回答是no ,至少在一般情况下不是这样,您不应该使用Collector来修改现有的collection。 原因是收集器被设计为支持并行性,即使是在不是线程安全的收集器上也是如此。 他们这样做的方法是让每个线程根据其自己的中间结果集合独立运行。 每个线程获取其自己的集合的方式是调用Collector.supplier() ,每次需要返回一个新的集合。 然后,再次以线程受限的方式合并这些中间结果的集合,直到只有一个结果集合为止。 这是collect()操作的最终结果。 来自Balder和assylias的几个答案建议使用Collectors.toCollection() ,然后传递一个供应商,该供应商返回现有列表而不是新列表。 这违反了供应商的要求,即每次都返回一个新的空集合。 如其答案中的示例所示,这将适用于简单的情况。 但是,它将失败,特别是如果流并行运行。 (该库的未来版本可能会以某种无法预料的方式更改