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

Java 使用Comparator.comparingLong比long.compare有什么优势?,java,java-8,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()

出于好奇,如果使用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方法参考
)是否有性能优势


请帮忙

唯一不同的是实现你想要的东西所需要的方法的数量
Comparator.comparingLong
将为每个参数应用一个
ToLong函数
,然后委托给
Long.compare
。但是这是一个简单的优化,
JIT
应该注意。我想说的是,由于这个差异,可能会有一个小的差异(直到JIT开始),但它是如此之小,是绝对可以忽略的,不应该以任何方式驱动您的决定


另一方面,如果您确实看到了任何差异,那么问题可能出在您的测试代码上,而不是被度量的代码。

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

在这两个变体之间选择的唯一标准是清晰性:您认为哪一个更清楚地表达了代码的意图?最后,这是一个个人偏好,取决于您对Java8特性的熟练程度以及其他方面


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

因此,这里从一个角度给出了答案,即性能

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

空调类:-

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();
        }
    }
}
对于
Long,请比较以下内容:-

# 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
虽然差别很小,但不知何故速度更快


如果您有任何发现,请随时发表评论,我也会尝试这些评论。

在收到有关使用的警告之前,我正在尝试对地图进行排序

(entry1,entry2)->Long.compare(entry1.getKey(),entry2.getKey())
应该使用Comparator.comparingLong替换它,结果确实是实现它的更好方法:

Comparator.comparingLong(Map.Entry::getKey)
检查comparingLong的实现时,我发现它基本上是相同的实现,只是它更干净、更省时

return (Comparator<T> & Serializable)
(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2))
返回(比较器&可序列化)
(c1,c2)->Long.比较(键提取器.applyAsLong(c1),键提取器.applyAsLong(c2))

任何差异都可以忽略不计。在“java.util.Comparator.comparingLong”方法中,您可以看到与第一个示例(c1,c2)->Long.compare(keydextractor.applyAsLong(c1),keydextractor.applyAsLong(c2))所做的事情相同的工程师喜欢测量这些事情。你能试着用10万次来衡量性能吗?如果能在答案部分看到你的发现,那就太好了。单个比较之间的任何性能差异都是无关的,最大的性能影响是由实际的排序造成的。如果您试图在性能基础上选择其中一种,那么您并不真正了解性能调优(或排序)。第二种变体的好处不是性能,而是简化。它更短,并且避免了代码重复。这不仅仅是一个理论观点;即使在如此短的代码片段中,例如
(a,b)->Long.compare(a.getId(),a.getId())
中,我也看到了复制和粘贴错误,您必须查看两次才能发现错误。如果您希望此特定代码段更快,请使用
listsortedacs=newarraylist(ac);sortedAcs.sort(Comparator.comparingLong(AC::getId))以就地排序。因此,基本上,即使在lambda表达式的情况下,性能受到的影响很小,性能也会受到影响。@VinayPrajapati这两个示例都使用lambdas。另一个只使用方法引用。耶!我的错。我的意思是使用方法references@VinayPrajapatilambdas和方法引用之间存在差异,但是否有任何重大影响值得怀疑。如果我计算一下的话,通常相差24毫秒。但是
Long的不确定性似乎更大。比较
。这些结果表明
comparingLong()
稍微快一点,它具有更高的吞吐量,但只有约0.6%。但是,
comparingLong()
更具可读性,而且由于它具有同样好或更好的性能,因此使用它是一个明确的选择。
return (Comparator<T> & Serializable)
(c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2))