Java流在创建不可变列表时会创建一些临时列表吗?

时间:2019-01-24 19:03:52

标签: java java-8 java-stream immutability

由于没有元素可以添加到不可变列表中,因此我认为java流首先将元素收集到列表中,然后使用第一个列表中的元素创建一个新的不可变列表。因此,该列表有两个实例,第一个实例可用于垃圾回收。

所以我的问题是

  1. 流实际上是否如上所述创建了两个列表对象?
  2. 如果没有,流如何创建不可变列表?

2 个答案:

答案 0 :(得分:4)

任何实现都将以某种方式将元素累积到具有某种可变性的结构中,然后返回无法修改的列表。

具体操作方法取决于实施,但这有几种可能性:

  • 元素被累积到ArrayList中,然后被复制到不可变列表中。
  • 将元素累积到ArrayList中,并返回防止修改的包装器(例如Collections.unmodifiableList。)由于没有其他对象引用原始ArrayList,因此结果是变得一成不变。
  • 元素被累积到某种技术上不是列表的结构中,例如原始数组,并且该数组被复制或包装在不可变的列表对象中。

选择哪种实现取决于您调用的特定Collector,例如Collectors.toList()ImmutableList.toImmutableList()。该实现的细节取决于该库的作者,他们可以使用任何这些策略。

答案 1 :(得分:2)

考虑以下示例:

List<String> people
         = getPeople().stream()
                      .collect(collectingAndThen(toList(), Collections::unmodifiableList));

在此示例中,我使用的是Collections::unmodifiableList方法,因此让我们检查源代码:

/**
 * Returns an unmodifiable view of the specified list.  This method allows
 * modules to provide users with "read-only" access to internal
 * lists.  Query operations on the returned list "read through" to the
 * specified list, and attempts to modify the returned list, whether
 * direct or via its iterator, result in an
 * <tt>UnsupportedOperationException</tt>.<p>
 *
 * The returned list will be serializable if the specified list
 * is serializable. Similarly, the returned list will implement
 * {@link RandomAccess} if the specified list does.
 *
 * @param  list the list for which an unmodifiable view is to be returned.
 * @return an unmodifiable view of the specified list.
 */
public static <T> List<T> unmodifiableList(List<? extends T> list) {
    return (list instanceof RandomAccess ?
            new UnmodifiableRandomAccessList<>(list) :
            new UnmodifiableList<>(list));
}

如@Pshemo的注释中所述,UnmodifiableList用作列表的包装器,您还可以在源代码中检查此类包含内部列表的源: / p>

 static class UnmodifiableList<E> extends UnmodifiableCollection<E>
                               implements List<E> {
     private static final long serialVersionUID = -283967356065247728L;
     final List<? extends E> list; // Here is the wrapped list

     UnmodifiableList(List<? extends E> list) {
         super(list);
         this.list = list;
     }
    ...
}

用于提取这些代码的源代码可以为found here

所以回答您的问题:

  • 流使用诸如Collections::unmodifiableList方法之类的方法创建不可变列表
  • 内部流不会在其他列表中添加任何内容,因为ImmutableList仅用作Collection的包装

您还可以签入文档和资源以了解这些不可变的相关方法和对象的工作原理。