我写了一个JMH基准来衡量这一点。其中有4种方法:
removeIf
在ArrayList
。removeIf
在linkedList
。- 迭代器
iterator.remove()
上ArrayList
。 - 迭代器
iterator.remove()
上linkedList
。
基准测试的目的是表明
removeIf和迭代器应提供相同的性能,但对于而言并非如此
ArrayList。
默认情况下,
removeIf内部使用迭代器删除元素,因此我们应该期望与
removeIf和具有相同的性能
iterator。
现在考虑一个
ArrayList在内部使用数组保存元素的。每次调用时
remove,索引后的其余元素都必须移动一个;因此每次必须复制很多元素。当使用迭代器遍历the
ArrayList且我们需要删除一个元素时,此复制需要一次又一次地进行,这会非常缓慢。对于a
linkedList,情况并非如此:删除元素时,唯一的更改是指向下一个元素的指针。
那么,为什么在a
removeIf上一样快?因为实际上它已被覆盖并且不使用迭代器,所以代码实际上在第一遍中标记了要删除的元素,然后在第二遍中删除了它们(移动其余元素)。在这种情况下,可以进行优化:与其在每次需要删除一个元素时都移动剩余元素,不如在知道所有需要删除的元素时只执行一次。
ArrayList``linkedList
结论:
removeIf
当需要删除与谓词匹配的所有元素时,应使用。remove
应该用于删除单个已知元素。
基准测试结果:
Benchmark Mode Cnt Score Error UnitsRemoveTest.removeIfArrayList avgt 30 4,478 ± 0,194 ms/opRemoveTest.removeIflinkedList avgt 30 3,634 ± 0,184 ms/opRemoveTest.removeIteratorArrayList avgt 30 27197,046 ± 536,584 ms/opRemoveTest.removeIteratorlinkedList avgt 30 3,601 ± 0,195 ms/op
基准测试:
@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.MILLISECONDS)@Fork(3)@State(Scope.Benchmark)public class RemoveTest { private static final int NUMBER_OF_LIST_INDEXES = 1_000_000; private static final String[] words = "Testing Lamba expressions with this String array".split(" "); private ArrayList<String> arrayList; private linkedList<String> linkedList; @Setup(Level.Iteration) public void setUp() { arrayList = new ArrayList<>(); linkedList = new linkedList<>(); for (int i = 0 ; i < NUMBER_OF_LIST_INDEXES ; i++){ arrayList.add(words[i%6]); linkedList.add(words[i%6]); } } @Benchmark public void removeIfArrayList() { arrayList.removeIf(x -> x.contains("s")); } @Benchmark public void removeIflinkedList() { linkedList.removeIf(x -> x.contains("s")); } @Benchmark public void removeIteratorArrayList() { for (ListIterator<String> it = arrayList.listIterator(arrayList.size()); it.hasPrevious();){ if (it.previous().contains("s")) it.remove(); } } @Benchmark public void removeIteratorlinkedList() { for (ListIterator<String> it = linkedList.listIterator(linkedList.size()); it.hasPrevious();){ if (it.previous().contains("s")) it.remove(); } } public static void main(String[] args) throws Exception { Main.main(args); }}


