This不是我的问题的重复项。我检查了一下,它更多地是关于内部匿名类的。
我对Lambda表达式感到好奇,并测试了以下内容:
最初的结果不足为奇,因为我不知道自己要提出什么:
final int NUMBER_OF_LIST_INDEXES = 10_000;
List<String> myList = new ArrayList<>();
String[] myWords = "Testing Lamba expressions with this String array".split(" ");
for (int i = 0 ; i < NUMBER_OF_LIST_INDEXES ; i++){
myList.add(myWords[i%6]);
}
long time = System.currentTimeMillis();
// BOTH TESTS WERE RUN SEPARATELY OF COURSE
// PUT THE UNUSED ONE IN COMMENTS WHEN THE OTHER WAS WORKING
// 250 milliseconds for the Lambda Expression
myList.removeIf(x -> x.contains("s"));
// 16 milliseconds for the traditional Loop
for (int i = NUMBER_OF_LIST_INDEXES - 1 ; i >= 0 ; i--){
if (myList.get(i).contains("s")) myList.remove(i);
}
System.out.println(System.currentTimeMillis() - time + " milliseconds");
但是随后,我决定将常量NUMBER_OF_LIST_INDEXES
更改为一百万,结果如下:final int NUMBER_OF_LIST_INDEXES = 1_000_000;
List<String> myList = new ArrayList<>();
String[] myWords = "Testing Lamba expressions with this String array".split(" ");
for (int i = 0 ; i < NUMBER_OF_LIST_INDEXES ; i++){
myList.add(myWords[i%6]);
}
long time = System.currentTimeMillis();
// BOTH TESTS WERE RUN SEPARATELY OF COURSE
// PUT THE UNUSED ONE IN COMMENTS WHEN THE OTHER WAS WORKING
// 390 milliseconds for the Lambda Expression
myList.removeIf(x -> x.contains("s"));
// 32854 milliseconds for the traditional Loop
for (int i = NUMBER_OF_LIST_INDEXES - 1 ; i >= 0 ; i--){
if (myList.get(i).contains("s")) myList.remove(i);
}
System.out.println(System.currentTimeMillis() - time + " milliseconds");
为了使内容更易于阅读,以下是结果:| | 10.000 | 1.000.000 |
| LAMBDA | 250ms | 390ms | 156% evolution
|FORLOOP | 16ms | 32854ms | 205000+% evolution
我有以下问题:List
方法的特定行为吗?其他Lambda表达式也会产生这种随机表现吗?最佳答案
我写了一个JMH基准来衡量这一点。其中有4种方法:removeIf
上的
ArrayList
。 removeIf
上的LinkedList
。 iterator.remove()
上带有ArrayList
的iterator.remove()
上使用LinkedList
的基准测试的目的是表明
removeIf
和迭代器应提供相同的性能,但ArrayList
并非如此。默认情况下,
removeIf
在内部使用迭代器删除元素,因此我们应该期望removeIf
和iterator
具有相同的性能。现在考虑一个
ArrayList
,它在内部使用一个数组来保存元素。每次我们调用remove
时,索引后的其余元素都必须移动一个;因此每次必须复制许多元素。当使用迭代器遍历ArrayList
时,我们需要删除一个元素,因此需要一次又一次地进行复制,这非常缓慢。对于LinkedList
,情况并非如此:删除元素时,唯一的更改是指向下一个元素的指针。那么,为什么
removeIf
在ArrayList
上和在LinkedList
上一样快?因为实际上它已被覆盖并且不使用迭代器,所以代码实际上在第一遍中标记了要删除的元素,然后在第二遍中删除了它们(移动其余元素)。在这种情况下,可以进行优化:与其在每次需要删除一个元素时都移动剩余元素,不如在知道所有需要删除的元素时只执行一次。结论:
当需要删除与谓词匹配的所有元素时,应使用
removeIf
。 remove
应该用于删除单个已知元素。 基准测试结果:
Benchmark Mode Cnt Score Error Units
RemoveTest.removeIfArrayList avgt 30 4,478 ± 0,194 ms/op
RemoveTest.removeIfLinkedList avgt 30 3,634 ± 0,184 ms/op
RemoveTest.removeIteratorArrayList avgt 30 27197,046 ± 536,584 ms/op
RemoveTest.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);
}
}
关于java - Lambda表现有差异吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33182102/