首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解除装箱会减慢Java流吗?

解除装箱会减慢Java流吗?
EN

Stack Overflow用户
提问于 2020-09-29 15:29:48
回答 2查看 328关注 0票数 0

我有以下课程:

代码语言:javascript
复制
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);
    }
}

这个类有两个方法,它们接收整数列表并返回最小的数字。一种方法是将Integer的compareTo()方法作为min()函数中的比较器传递。另一种方法是从列表中获取一个IntStream,并对其调用min()函数。

第二种方法使用取消装箱来映射包装的int。取消装箱是著名的缓慢时,使用频繁,但我看不到使用和不使用它在这个程序之间的区别。

哪条路更快?或者他们俩是一样的?

谢谢。

编辑:

我采纳了Code-学徒的建议,并使用以下方法进行了大量测量:

代码语言:javascript
复制
    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倍。为什么会这样呢?

输出:

代码语言:javascript
复制
4.166 no unboxing seconds
1.922 with unboxing seconds
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-29 16:43:29

取消装箱只不过是读取Integer对象的Integer字段的值。这不能减缓操作的速度,至于与其他变体中的Integer实例相比,也必须读取这些字段。

因此,这些操作在不同的抽象上工作。

当您使用mapToInt(x -> x)时,您使用的是一个ToIntFunction来告诉实现如何获取int值,然后,min操作直接在int值上工作。

当您使用min(Integer::compareTo)时,您使用的是一个Comparator来告诉泛型实现,哪个对象比另一个小。

基本上,这些操作相当于

代码语言:javascript
复制
private Optional<Integer> minNoUnboxing(List<Integer> list) {
    Comparator<Integer> c = Integer::compareTo;

    if(list.isEmpty()) return Optional.empty();
    Integer o = list.get(0);
    for(Integer next: list.subList(1, list.size())) {
        if(c.compare(o, next) > 0) o = next;
    }
    return Optional.of(o);
}

private OptionalInt minWithUnboxing(List<Integer> list) {
    ToIntFunction<Integer> toInt = x -> x;

    if(list.isEmpty()) return OptionalInt.empty();
    int i = toInt.applyAsInt(list.get(0));
    for(Integer next: list.subList(1, list.size())) {
        int nextInt = toInt.applyAsInt(next);
        if(i > nextInt) i = nextInt;
    }
    return OptionalInt.of(i);
}

除非运行时优化器消除了所有差异,否则对于较大的列表,我希望取消装箱版本会更快,因为取消装箱为每个元素提取一次int字段,而compareTo必须为每个比较提取两个int值。

票数 4
EN

Stack Overflow用户

发布于 2020-09-29 17:23:23

性能影响几乎与解除装箱几乎没有任何关系,与您正在比较两个根本不同的操作(比较器与缩减的最小化)有关。

见以下基准:

代码语言:javascript
复制
@Benchmark
public Integer minNoUnboxing(BenchmarkState state) {
    return state.randomNumbers.stream().min(Integer::compareTo).orElse(-1);
}

@Benchmark
public Integer minNoUnboxingReduce(BenchmarkState state) {
    return state.randomNumbers.stream().reduce((a, b) -> a < b ? a : b).orElse(-1);
}

@Benchmark
public Integer minWithUnboxingReduce(BenchmarkState state) {
    return state.randomNumbers.stream().mapToInt(x -> x).min().orElse(-1);
}

结果:

代码语言:javascript
复制
Benchmark                          (listSize)   Mode  Cnt    Score    Error  Units
MyBenchmark.minNoUnboxing             1000000  thrpt    5  128.585 ± 17.617  ops/s
MyBenchmark.minNoUnboxingReduce       1000000  thrpt    5  317.772 ± 27.659  ops/s
MyBenchmark.minWithUnboxingReduce     1000000  thrpt    5  300.348 ± 23.458  ops/s

编辑:还请注意,与装箱相比,取消装箱非常快速。在最坏的情况下,取消装箱只是字段访问/指针取消引用,而装箱则可能涉及对象实例化。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64122809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档