只是好奇...有更好的方法复制/克隆ArrayList的一部分吗?

4

有没有比我现在这种方式更高效/更快/更明智的复制ArrayList一部分的方法?

 public ArrayList<FooObject> getListOfFlagged() {    
        for(FooObject fooObject: foos) {
            //for each item in the original array, where the item isFlagged...
            if(fooObject.isFlagged) {
                someOtherArray.add(fooObject);
            }
        }    
        return someOtherArray;
    }
4个回答

3
您可以使用Guava中的Collections2.filter()方法,它具有更多的函数特性:
    Collections2.filter(foos, new Predicate<FooObject>() {
        @Override
        public boolean apply(FooObject input) {
            return fooObject.isFlagged();
        }
    })

这个结果是基于你原来的 foos 集合,所以如果你需要一份拷贝,你需要使用 new ArrayList<FooObject>(filteredCollection) 来进行防御性拷贝。


由于过滤集合不存储标记元素的副本,因此在大多数情况下,它将比原始代码使用更少的内存。但是,对过滤集合的每次访问都将遍历支持foos集合。因此,访问元素需要更长的时间。如果您关心RAM但可以浪费CPU,那么可以使用这个。 - Florian

1

使用 Guava:

    class FooObject{boolean isFlagged(){return true;}}      
    List<FooObject> foos = Lists.newArrayList();
    Lists.newArrayList(
        Iterables.filter(foos, new Predicate<FooObject>(){
            @Override public boolean apply(FooObject input) {
                return input.isFlagged();
            };
        })
    );

0
一个重要的优化是预先分配“someOtherArray”中元素的数量,否则它会进行许多重新分配操作——当然,这取决于你处理的项目数量。由于我们事先不知道结果大小,最简单的方法是使用foos的大小设置someOtherArray的容量。
someOtherArray.ensureCapacity(foos.size());

当然,如果foos很大,只有少数项目通常被标记,这将没有意义。

还要注意,您的方法应该先清除一些其他数组。

我能想到的另一个优化是如何访问foos的元素。您可以尝试使用典型的for(int i = 0; i<size; i ++)循环,并使用foos.get(i)初始化fooObject。如果“扩展for”是通过获取元素的副本或可能也是获取迭代器来实现的,则该方式可能更快。但是,我认为在ArrayList上迭代接收特殊优化编译器...也许其他人在这个领域有经验。


在我的答案中,我尝试保持返回的ArrayList的访问效率,同时减少创建返回列表时的时间和垃圾收集器工作量。 - Florian

0

没有,除非你对需要复制的元素的位置有特殊了解。

比如说,如果你需要复制一个包含50个元素的数组中的第10到19个元素,那么分配一个包含10个元素的数组并使用System.arrayCopy()会更快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接