You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Comparator.comparingInt的Lambda与方法引用使用及原理的咨询

你的测试代码

public static void main(String[] args) {
        Student[] students = new Student[4];
        students[0] = new Student("guy1", 103, 334); // height / age (随便写的)
        students[1] = new Student("guy2", 87, 534);
        students[2] = new Student("guy3", 103, 232);
        students[3] = new Student("guy4", 110, 121);

        Arrays.sort(students, Comparator.comparingInt(Student::getAge)); // 方法引用
        Arrays.sort(students, Comparator.comparingInt(student -> student.getAge())); // Lambda表达式
}

comparingInt方法源码

// comparingInt方法的源码
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
 Objects.requireNonNull(keyExtractor);
 return (Comparator<T> & Serializable)
             (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}

你尝试过的错误写法

// 类似这样的写法都无法通过IDEA校验
Arrays.sort(students, Comparator.comparingInt(students,c1,getAge));

// 你熟悉的匿名内部类写法(对比用)
//        Animal a = new Animal() {
//            @Override
//            public void run() {
//                System.out.println("dog runs");
//            }
//        };

//        Animal a = () -> {
//            System.out.println("dog runs");
//        };
//
//        a.run();

核心问题解答

1. 为什么不能直接传对象和方法?

comparingInt要的不是具体的Student对象或者方法本身,而是一个**“从任意Student对象中提取int类型值”的规则**——这个规则由ToIntFunction接口定义:接收一个T类型(这里是Student)的参数,返回int。

你尝试的comparingInt(students,c1,getAge)写法完全不符合参数要求,因为该方法只接受一个参数:实现了ToIntFunction的实例,而非一堆对象、变量名。

2. Lambda和方法引用为什么能行?

它们本质上都是ToIntFunction接口的简化实现,和你写Animal的匿名内部类逻辑一致:

  • Lambda表达式:student -> student.getAge() 就是在实现ToIntFunction的applyAsInt方法——输入一个Student对象,返回它的age值。
  • 方法引用:Student::getAge 是Lambda的语法糖,因为getAge()方法的签名刚好匹配ToIntFunction的要求:接收Student,返回int,编译器会自动把它适配成ToIntFunction的实例。

3. 结合源码看逻辑

从comparingInt的源码能清楚看到:

  • 它接收的keyExtractor是提取规则,返回一个Comparator。
  • 这个返回的Comparator在比较两个对象c1和c2时,会调用keyExtractor.applyAsInt(c1)和keyExtractor.applyAsInt(c2),拿到两个int值后用Integer.compare做比较。

也就是说,你不需要提前给它具体的Student对象,排序时Arrays.sort会自动把数组里的每一对Student对象传给这个Comparator,而keyExtractor负责从每个对象里拿出要比较的字段值——这才是这个方法的设计逻辑:把“提取比较字段”和“比较逻辑”解耦,你只需要告诉它怎么拿值,剩下的比较逻辑由方法帮你实现。

4. 对比你熟悉的匿名内部类

如果不用Lambda和方法引用,用匿名内部类写ToIntFunction的话,是这样的:

Comparator<Student> comparator = Comparator.comparingInt(new ToIntFunction<Student>() {
    @Override
    public int applyAsInt(Student student) {
        return student.getAge();
    }
});
Arrays.sort(students, comparator);

和你写Animal的匿名内部类完全一样,Lambda和方法引用只是把这段代码简化成了一行而已。


内容的提问来源于stack exchange,提问作者Clarence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:24:52