我使用JMH来测试Lambda对Anonymous Inner类的性能,以下是我的做法:
public class LambdaVsAnonymousClass {
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void testLambda() {
// nonCapturing expressions
NonCapturing nonCapturing = () -> System.out.println("ram");
nonCapturing.test();
// nonCapturing expressions
NonCapturing nonCapturing2 = () -> System.out.println("bon");
nonCapturing2.test();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void testAnonymousClass() {
// anonymous classes
NonCapturing nonCapturing = new NonCapturing() {
@Override
public void test() {
System.out.println("ram");
}
};
nonCapturing.test();
// anonymous classes
NonCapturing nonCapturing2 = new NonCapturing() {
@Override
public void test() {
System.out.println("bon");
}
};
nonCapturing2.test();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void testLambdaCapturing() {
// lambda expressions
final int i = 1;
Capturing capturing = n -> System.out.println(n);
capturing.test(i);
// lambda expressions
final int j = 2;
Capturing capturing2 = n -> System.out.println(n);
capturing2.test(j);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public void testAnonymousClassCapturing() {
// anonymous classes
final int i = 1;
Capturing capturing = new Capturing() {
@Override
public void test(int n) {
System.out.println(n);
}
};
capturing.test(i);
// anonymous classes
final int j = 2;
Capturing capturing2 = new Capturing() {
@Override
public void test(int n) {
System.out.println(n);
}
};
capturing2.test(j);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(LambdaVsAnonymousClass.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(5)
.forks(1)
.build();
new Runner(opt).run();
}
}
@FunctionalInterface
interface NonCapturing {
void test();
}
@FunctionalInterface
interface Capturing {
void test(int n);
}
我期待Lambda完成得更快,但我得到了相反的结果。我错误地测试了吗?如果是,那么实际测试lambda表达式的更快性能的正确方法是什么。
# Run complete. Total time: 00:00:42
Benchmark Mode Cnt Score Error Units
LambdaVsAnonymousClass.testAnonymousClass avgt 5 16.592 ± 4.084 us/op
LambdaVsAnonymousClass.testAnonymousClassCapturing avgt 5 18.916 ± 4.469 us/op
LambdaVsAnonymousClass.testLambda avgt 5 18.618 ± 4.060 us/op
LambdaVsAnonymousClass.testLambdaCapturing avgt 5 22.008 ± 16.729 us/op
注意:捕获lambda表达式的概念在代码中显示不正确。阅读@Holger的评论以获得更多理解。
答案 0 :(得分:2)
目前还不是很清楚你究竟想要测试什么。创建然后调用?如果是这样,那么删除System.out,因为它们咬你很糟糕,然后输出应该以纳秒为单位进行测量。
在这种情况下(毫不奇怪)结果大致相同:
LambdaVsClass.testAnonymousClass avgt 5 0.335 ± 0.069 ns/op
LambdaVsClass.testAnonymousClassCapturing avgt 5 0.337 ± 0.051 ns/op
LambdaVsClass.testLambda avgt 5 0.331 ± 0.051 ns/op
LambdaVsClass.testLambdaCapturing avgt 5 0.337 ± 0.043 ns/op
如果你测量SingleShotTime作为invokedynamic(没有任何预热)引导lambda,结果应该不同。
答案 1 :(得分:2)
您应该对基准测试结果至关重要,并了解您所看到的内容。 ±4
的错误大于16.6
和18.6
的“非捕获”测试执行时间的执行时间之间的差异。
当你看到22
的结果,错误为±16.7
时,它肯定会响起警钟!
另外,你对“捕获”的理解有误。在测试中,没有捕获lambda表达式或匿名类。您只有一个零参数的函数和一个带有一个参数的函数。这与捕获无关。唯一的区别是,在一种情况下,您要打印现有的String
,而在另一种情况下,您正在执行int
到String
转换。但即使这些差异也小于报告的误差。
在考虑错误时,结果的幅度相同,当然,打印代码的性能不取决于它是驻留在lambda表达式还是匿名内部类中。目前尚不清楚为什么你期望lambda表达式更快。 Lambda表达式并不神奇。