【问题标题】:Does java stream create some temporary list while creating Immutable List?java流在创建不可变列表时是否会创建一些临时列表?
【发布时间】:2019-01-24 19:03:51
【问题描述】:

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

所以,我的问题是

  1. 流是否真的创建了上面提到的两个列表对象?
  2. 如果不是,流如何创建不可变列表?

【问题讨论】:

  • 您使用什么特定代码从流中创建不可变列表?
  • 是什么让您认为流正在创建不可变集合?您的问题似乎是基于我没有看到任何基础的断言,例如Collectors.toList() 并没有说它创建了一个不可变的列表。
  • 您为什么认为使用临时列表创建不可变列表需要副本?
  • 您的问题似乎需要澄清,因为它与您在 your 第二条评论中描述的问题不同。此外,如果您询问如何 通过流创建不可变列表,您可以使用 stream.collect(collectingAndThen(toList(), Collections::unmodifiableList)); 之类的构造。正如 Louis 提到的(可能没有明确说明,但我认为这是有意的)Collections.unmodifiableList(list) 不需要从 list 复制任何元素,它只是创建 wrapper 列表类,它将处理一个适合不可变类的方式。
  • 您在问 Java 流如何创建不可变列表。 没有。如果您想要一个具有与流实现代码提供的默认列表不同的特征(例如不可变)的列表,那么为此提供代码。所以看起来你真的在问:我该怎么做?这是你的问题吗?如果是这样,请编辑问题并澄清它。

标签: java java-8 java-stream immutability


【解决方案1】:

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

如何完成的细节取决于实现,但这里有几种可能性:

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

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

【讨论】:

  • 来自Collectors.toList() 的 API 文档:“无法保证返回的列表的类型、可变性、可序列化性或线程安全性。”就目前而言,这个问题太宽泛,无法很好地回答。
  • @AndyThomas 从 11 开始也有 Collectors::toUnmodifiableList
【解决方案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 在 cmets 中提到的,UnmodifiableList 可作为列表的包装器,您还可以在源代码中查看此类包含列表的源代码:

 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 的包装器工作

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

【讨论】:

    猜你喜欢
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 2022-06-17
    • 2017-03-26
    • 2011-06-09
    • 1970-01-01
    • 2015-08-01
    相关资源
    最近更新 更多