使用Comparator.comparingLong比long.compare有什么优势?

时间:2017-10-25 04:56:42

标签: java java-8

出于好奇,如果在java8风格中使用Comparator,即使用Lambda表达式比常规比较有任何优势,即

按ID排序的一种方法是: -

List sortedAcs = ac
.stream()
.sorted((a, b) -> Long.compare(a.getId(), b.getId())) //sorted by id here
.collect(Collectors.toList());

其他方法可能是Java 8方式: -

List sortedAcs = ac
.stream()
.sorted(Comparator.comparingLong(AC::getId)) //sorted by id here
.collect(Collectors.toList());

以后的方法(java-8 method reference)与以前的方法相比,是否有任何性能优势?

请帮助!!!

4 个答案:

答案 0 :(得分:7)

唯一不同的是完成你想要的方法所需的方法数量。 Comparator.comparingLong会为每个参数应用ToLongFunction,然后然后委托给Long.compare。但这是一个JIT应该处理的简单优化。我会说因为这个差异,可能会有一点点差异(直到JIT开始),但它会如此之小,以至于绝对可以忽略,不应该以任何方式推动你的决定。

另一方面,如果您确实发现任何差异,那么可能是您的测试代码是问题,而不是正在测量的代码。

答案 1 :(得分:2)

两个代码段中的任何性能差异都是可以忽略的。如果你真的需要优化代码,那么不使用流可能会比替换比较器提供更大的性能提升。

您应该使用两种变体进行选择的唯一标准是清晰度:您认为哪一个更清楚地传达了代码的意图?最后,这是个人偏好,取决于您对Java 8功能的流畅程度等等。

就个人而言,我发现第二个片段比第一个片段更清晰。 comparingLong方法(以及其他comparingX方法)立即告诉我:这里我们基于(long - typed)属性的值来比较对象。在第一个片段中,我首先需要解析代码以确定确实发生了什么。

答案 2 :(得分:1)

所以,从一个角度来看答案,即表现。

以下是我用来测试它的代码: -

AC课程: -

package com.test;

public class AC {

    private Long id;

    public AC(Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "AC{" +
                "id=" + id +
                '}';
    }
}

主要课程: -

package test.java;

import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Main {

    @org.openjdk.jmh.annotations.Benchmark
    public void measureName() {
        List<AC> acs = new ArrayList<>();

        acs.add(new AC(20l));
        acs.add(new AC(30l));
        acs.add(new AC(10l));
        acs.add(new AC(30l));
        acs.add(new AC(80l));
        acs.add(new AC(50l));
        acs.add(new AC(30l));
        acs.add(new AC(90l));
        acs.add(new AC(80l));
        acs.add(new AC(110l));

   /*     acs
                .stream()
                .sorted(Comparator.comparingLong(AC::getId)) //sorted by id here
                .collect(Collectors.toList());*/

        acs.stream()
                .sorted((a, b) -> Long.compare(a.getId(), b.getId())) //sorted by id here
                .collect(Collectors.toList());

    }

    public static void main(String[] args) {

        Options opt = new OptionsBuilder()
                .include(".*" + Main.class.getSimpleName() + ".*")
                .forks(1)
                .build();

        try {
            new Runner(opt).run();
        } catch (RunnerException e) {
            e.printStackTrace();
        }
    }
}

使用JMH将以下输出用于Comparator.comparingLong: -

# Run complete. Total time: 00:00:40

Benchmark          Mode  Cnt        Score       Error  Units
Main.measureName  thrpt   20  4130836.283 ± 86675.431  ops/s

以及下面的Long.compare: -

# Run complete. Total time: 00:00:40

Benchmark          Mode  Cnt        Score        Error  Units
Main.measureName  thrpt   20  4106542.318 ± 146956.814  ops/s

如果我按照这些统计数据Long.compare以某种方式更快,但差异很小。

如果有的话,请随时发表评论,我也会尝试。

答案 3 :(得分:0)

我在收到有关

使用的警告之前,试图对地图进行排序
(entry1,entry2)->Long.compare(entry1.getKey(),entry2.getKey())

应使用Comparator.comparingLong替换它,结果是实现它的更好方法:

Comparator.comparingLong(Map.Entry::getKey)

在对compareLong的实现进行检查时,我发现它基本上是相同的实现,只是它更干净且耗时更少。

return (Comparator<T> & Serializable)
(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2))