当前位置: 首页 > 知识库问答 >
问题:

当我需要调整源列表时,addAll 的最有效等效项是什么?

郎献
2023-03-14

如果我想将一个列表添加到另一个列表中,我调用< code > target . adall(source)。

但是,如果我需要首先处理列表中的每个值怎么办?

我可以这样做

for(String s: source) {
  target.add(s.toLowerCase());
}

或者使用java 8:

source.stream().map(x->x.toLowerCase()).forEachOrdered(target::add);

但无论哪种方式,我似乎都失去了<code>addAll<code>的性能优势。最有效的方法是什么?

共有2个答案

林昱
2023-03-14

您可以使用 Eclipse 集合中的收集() 模式,收集() 等效于来自 JDK 的 map()

MutableList<String> source = Lists.mutable.with("A", "B", "C");
MutableList<String> target = source.collect(String::toLowerCase);

如果您有现有的目标列表,则可以使用接受目标集合的 collect() 变体:

MutableList<String> source = Lists.mutable.with("A", "B", "C");
source.collect(String::toLowerCase, target);

如果您无法从< code>List更改列表:

List<String> source = Arrays.asList("A", "B", "C");
List<String> target = ListAdapter.adapt(source).collect(String::toLowerCase);

您还可以在List上使用replace eAll()

List<String> source = Arrays.asList("A", "B", "C");
List<String> target = new ArrayList<>(source);
target.replaceAll(String::toLowerCase);

上面的解决方案可能性能更好,也可能性能更差,但是,它们都预先确定了目标列表的大小。

祁晟
2023-03-14

那么,什么是“添加全部的性能优势”?最后,addAll 无论如何都必须将所有元素添加到目标集合中。如果目标是数组列表,则主要好处是确保没有不必要的容量增加操作。

但是请注意,这是以创建临时数组为代价的,请参见<code>ArrayList.addAll<code>的实现。为了超过这一费用,您必须添加大量元素。

如果我们要添加比目标当前容量更多的元素,增加操作是不可避免的。所以< code>addAll只提供一个好处,如果目标必须增加一次以上的容量,而您只需使用< code>add。由于容量增加了1.5倍,并且容量等于或高于当前大小,因此我们必须添加至少超过其当前大小一半的元素,以应对不必要的容量增加操作。

如果你真的认为这将是一个问题,很容易解决:

if(target instanceof ArrayList)
    ((ArrayList)target).ensureCapacity(target.size()+source.size());
source.stream().map(String::toLowerCase).forEachOrdered(target::add);

当然,在某些情况下,add的成本要高得多,例如CopyOnWriteArrayList。对于这种目标集合类型,首先通过收集(Collectors.toList())收集到List中,然后是addAll可能是有益的。或者您创建一个简单的惰性集合作为中间步骤:

public static <T> Collection<T> lazyCollection(Supplier<? extends Stream<T>> s) {
    return new AbstractCollection<T>() {
        public Iterator<T> iterator() { return s.get().iterator(); }
        public int size() { return (int)s.get().count(); }
        public Object[] toArray() { return s.get().toArray(); }
    };
}

其可以如下使用:

target.addAll(lazyCollection(() -> source.stream().map(String::toLowerCase)));

如果一个集合在获取< code >迭代器之前首先请求< code>size(),那么这种方法会遇到两次流求值的问题,但是没有一个标准集合会这样做。它们或者使用迭代器而不依赖于预测的大小,或者求助于< code>toArray(),就像< code>ArrayList.addAll或< code > copyonwritearraylist . addall 所做的那样。

 类似资料:
  • 问题内容: LINQ的Java等效项是什么? 问题答案: 现在使用Java 8向我们介绍了Stream API,这在处理集合时是类似的事情,但与Linq不太一样。 如果它是您正在寻找的ORM,例如Entity Framework,那么您可以尝试Hibernate

  • 问题内容: 我想保持我的依赖关系为最新。使用Node.js,我运行(及更高版本)。 Go mod最接近的是什么? 理想情况下,我会看到有关项目的过时依赖关系的报告(并非全部都是递归的)。谢谢 问题答案: 列出直接和间接依赖 Go 1.11模块:如何升级和降级依赖项 Wiki中对此进行了详细说明: 要查看所有直接和间接依赖项的可用次要和补丁升级,请运行。 要将当前模块的所有直接和间接依赖关系升级到最

  • 问题内容: 有Swift的等效项吗?在中,我们通常使用: 如何在Swift中实现相同目标?我发现了一个功能: 但是,它很长,根本不方便。 问题答案: 将在斯威夫特的世界同样存在。 的,和参数均标有 该装置的同时调用该函数我们可以忽略这些参数的关键字。在这种情况下,将使用其默认值。 这得出一个结论,该方法调用可以简化为: Swift 5- 没什么变化,仍然可以这样工作。

  • 问题内容: 在Objective-C中,我使用以下代码删除所有子视图: 但是如何迅速使用它呢?我看到苹果文档迅速使用了该方法 但是当我尝试它时,出现错误: 有什么方法可以快速删除子视图? 问题答案: 已针对Swift 2.0(Xcode 7)更新 用途: 或像这样:

  • 问题内容: 在TSQL中,我可以声明: 在MySQL中,我无法编写相同的查询。 在MySQL中编写此查询的正确方法是什么? 问题答案: 行尾的分号。

  • 问题内容: PHP具有 var_dump()函数,该函数输出对象的内部内容,显示对象的类型和内容。 例如: 将输出: Java中将执行相同操作的等效项是什么? 问题答案: 它不是Java中的嵌入式程序,因此您不会免费获得它。 它是通过约定而不是语言构造完成的。在所有数据传输类中(甚至 在您编写的所有类中…… ),您都应该实现一个明智的方法。因此,这里您需要在您的类中重写并返回所需的状态。 有一些实