【发布时间】:2020-09-29 15:29:48
【问题描述】:
我有以下课程:
public final class App {
private App() {
}
public static void main(String[] args) {
Stopwatch stopwatch = Stopwatch.createStarted();
new App().main();
System.out.println(((double) stopwatch.elapsed(TimeUnit.MICROSECONDS) * 1_000_000) + " seconds!");
}
private void main() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
list.add(ThreadLocalRandom.current().nextInt(1000));
}
System.out.println(minNoUnboxing(list));
System.out.println(minWithUnboxing(list));
}
private Integer minNoUnboxing(List<Integer> list) {
return list.stream().min(Integer::compareTo).orElse(-1);
}
private Integer minWithUnboxing(List<Integer> list) {
return list.stream().mapToInt(x -> x).min().orElse(-1);
}
}
这个类有 2 个方法,它们接受一个整数列表并返回最小的数字。一种方法是在 min() 函数中将 Integer 的 compareTo() 方法作为比较器传递。另一种方法是从列表中获取一个 IntStream 并在其上调用 min() 函数。
第二种方法使用拆箱来映射包装的整数。拆箱以频繁使用时速度慢而闻名,但我看不出在这个程序中使用和不使用它的区别。
哪种方式更快?或者它们都一样?
谢谢。
编辑:
我接受了 Code-Apprentice 的建议,并使用这种方法进行了一系列测量:
Stopwatch noUnboxing = Stopwatch.createStarted();
for (int i = 0; i < 1000; i++) {
minNoUnboxing(list);
}
System.out.println((double) noUnboxing.elapsed(TimeUnit.MILLISECONDS) / 1000 + " no unboxing seconds");
Stopwatch withUnboxing = Stopwatch.createStarted();
for (int i = 0; i < 1000; i++) {
minWithUnboxing(list);
}
System.out.println((double) withUnboxing.elapsed(TimeUnit.MILLISECONDS) / 1000 + " with unboxing seconds");
事实证明,拆箱实际上比第一种方式快 2 倍。这是为什么呢?
输出:
4.166 no unboxing seconds
1.922 with unboxing seconds
【问题讨论】:
-
找出答案的一种方法是在代码中添加一些时间测量。将每个版本运行一百万次并比较平均值。
-
您的基准测试方法可能需要重新审视:How do I write a correct micro-benchmark in Java?
-
试试这个 - How do I write a correct micro-benchmark in Java? 并带着结果回来问一个更有趣的问题。
-
我做了一些测量,发现拆箱速度更快。为什么会这样?
-
我总是有一个燃烧期,您在测量之前执行两个循环。这样您就不必处理 JIT 预热时间。在那之后你仍然得到相同的值吗?
标签: java performance java-stream