我在探索Java 8源代码时,发现这部分代码非常令人惊讶:

//defined in IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
    return evaluate(ReduceOps.makeInt(op));
}

@Override
public final OptionalInt max() {
    return reduce(Math::max); //this is the gotcha line
}

//defined in Math.java
public static int max(int a, int b) {
    return (a >= b) ? a : b;
}

Math::max有点像方法指针吗?

推荐答案

通常,人们会使用Math.max(int, int)调用reduce方法,如下所示:

reduce(new IntBinaryOperator() {
    int applyAsInt(int left, int right) {
        return Math.max(left, right);
    }
});

仅呼叫Math.max就需要大量语法.这就是lambda表达式发挥作用的地方.从Java8开始,它被允许以更短的方式做同样的事情:

reduce((int left, int right) -> Math.max(left, right));

这是怎么回事?java编译器"检测"您想要实现一个接受两个int并返回一个int的方法.这相当于接口IntBinaryOperator的唯一方法的形式参数(要调用的方法reduce的参数).因此,编译器会为您完成其余的工作——它只是假设您想要实现IntBinaryOperator.

但由于Math.max(int, int)本身满足IntBinaryOperator的正式要求,因此可以直接使用.由于Java 7没有任何允许将方法本身作为参数传递的语法(您只能传递方法结果,但不能传递方法引用),因此在Java 8中引入了::语法来引用方法:

reduce(Math::max);

请注意,这将由编译器解释,而不是由JVM在运行时解释!虽然它为所有三个代码段生成不同的字节码,但它们在语义上是相等的,因此后两个可以被认为是上述IntBinaryOperator个实现的简短(可能更高效)版本!

(另见第Translation of Lambda Expressions页)

Java相关问答推荐

如何在Spring Boot中创建500错误的响应正文?

找到允许的最大底片

Quarkus keycloat配置不工作.quarkus. keycloak. policy—enforcer. enable = true在. yaml表示中不工作

如何使用AWS CLI从S3存储桶中的所有对象中删除用户定义的元数据?

Hibernate 6支持Joda DateTime吗?

使用传递的参数构造异常的Mockito-doThrow(或thenThrow)

获取字符串中带空格的数字和Java中的字符

为什么使用JDK21获取锁定锁比使用JDK11慢

基于配置switch 的@Controller的条件摄取

如果第一位数字和最后一位数字相差超过一位,您将如何获得随机数?

使用SWIG将C++自定义单元类型转换为基本Java类型

判断重复的两个二维表算法?

JPA无手术同品种器械可能吗?

通过/失败的参数化junit测试方法执行数

从字节数组切换到JakartaMail org.springframework.mail.javamail.JavaMailSender InputStreamResource

HBox内部的左对齐按钮(如果重要的话,在页码内)

原始和参数化之间的差异调用orElseGet时可选(供应商)

无泄漏函数的Java DRY

Java 21保护模式的穷尽性

java 11上出现DateTimeParseException,但java 8上没有