我正在探索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
static
IntBinaryOperator
网友回答:
::
称为方法引用。它基本上是对单个方法的引用。即,它按名称引用现有方法。
简短解释:
下面是对静态方法的引用示例:
class Hey {
public static double square(double num){
return Math.pow(num, 2);
}
}
Function<Double, Double> square = Hey::square;
double ans = square.apply(23d);
square
可以像对象引用一样传递,并在需要时触发。事实上,它可以像对对象的“正常”方法一样容易地用作参考。例如:static
class Hey {
public double square(double num) {
return Math.pow(num, 2);
}
}
Hey hey = new Hey();
Function<Double, Double> square = hey::square;
double ans = square.apply(23d);
Function
以上是一个功能界面。为了充分理解,理解功能接口也很重要。显然,函数接口是只有一个抽象方法的接口。::
功能接口的示例包括 、 和 。Runnable
Callable
ActionListener
Function
以上是一个只有一种方法的功能接口:。它接受一个参数并产生结果。apply
s之所以很棒,是因为:::
方法引用是与 lambda 表达式 (…) 具有相同处理的表达式,但它们不是提供方法主体,而是按名称引用现有方法。
例如,而不是编写 lambda 体
Function<Double, Double> square = (Double x) -> x * x;
你可以简单地做
Function<Double, Double> square = Hey::square;
在运行时,这两种方法的行为完全相同。字节码可能相同,也可能不同(但是,对于上述情况,会生成相同的字节码;编译上述内容并检查)。square
javap -c
唯一要满足的主要标准是:您提供的方法应与您用作对象引用的功能接口的方法具有类似的签名。
以下为非法:
Supplier<Boolean> p = Hey::square; // illegal
square
需要一个参数并返回一个 .供应商中的方法返回一个值,但它不接受参数。因此,这会导致错误。double
get
方法引用是指功能接口的方法。(如前所述,每个功能接口只能有一个方法。
再举一些例子:Consumer 中的方法接受输入,但它不返回任何内容。accept
Consumer<Integer> b1 = System::exit; // void exit(int status)
Consumer<String[]> b2 = Arrays::sort; // void sort(Object[] a)
Consumer<String> b3 = MyProgram::main; // void main(String... args)
class Hey {
public double getRandom() {
return Math.random();
}
}
Callable<Double> call = hey::getRandom;
Supplier<Double> call2 = hey::getRandom;
DoubleSupplier sup = hey::getRandom;
// Supplier is functional interface that takes no argument and gives a result
上面,不接受任何参数并返回 .因此,任何满足以下条件的功能接口都可以使用:不带参数并返回。getRandom
double
double
再比如:
Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("leo","bale","hanks"));
Predicate<String> pred = set::contains;
boolean exists = pred.test("leo");
如果是参数化类型:
class Param<T> {
T elem;
public T get() {
return elem;
}
public void set(T elem) {
this.elem = elem;
}
public static <E> E returnSame(E elem) {
return elem;
}
}
Supplier<Param<Integer>> obj = Param<Integer>::new;
Param<Integer> param = obj.get();
Consumer<Integer> c = param::set;
Supplier<Integer> s = param::get;
Function<String, String> func = Param::<String>returnSame;
方法引用可以有不同的样式,但从根本上说它们都意味着相同的内容,可以简单地可视化为 lambda:
ClassName::methName
)instanceRef::methName
)super::methName
)ClassName::methName
)ClassName::new
)TypeName[]::new
)有关进一步参考,请参阅 Lambda 的状态。
网友回答:
通常,将按如下方式调用该方法:reduce
Math.max(int, int)
reduce(new IntBinaryOperator() {
int applyAsInt(int left, int right) {
return Math.max(left, right);
}
});
这需要大量的语法来调用 .这就是 lambda 表达式发挥作用的地方。从Java 8开始,它被允许以更短的方式做同样的事情:Math.max
reduce((int left, int right) -> Math.max(left, right));
这是如何工作的?java编译器“检测”,你想要实现一个接受两个s并返回一个的方法。这相当于接口的唯一方法(要调用的方法的参数)的形式参数。因此,编译器会为您完成其余的工作 – 它只是假设您要实现.int
int
IntBinaryOperator
reduce
IntBinaryOperator
但由于它本身满足 的形式要求,因此可以直接使用。由于 Java 7 没有任何语法允许将方法本身作为参数传递(您只能传递方法结果,而不能传递方法引用),因此在 Java 8 中引入了该语法来引用方法:Math.max(int, int)
IntBinaryOperator
::
reduce(Math::max);
请注意,这将由编译器解释,而不是由运行时的 JVM 解释!虽然它为所有三个代码片段生成不同的字节码,但它们在语义上是相等的,因此最后两个可以被认为是上述实现的简短(可能更有效)版本!IntBinaryOperator
(另请参阅lambda表达式的翻译)
网友回答:
是的,这是真的。运算符用于方法引用。因此,可以使用它从类中提取静态方法,也可以从对象中提取方法。甚至可以将同一运算符用于构造函数。下面的代码示例中举例说明了此处提到的所有情况。::
Oracle 的官方文档可以在这里找到。
您可以在本文中更好地了解 JDK 8 的更改。在方法/构造函数引用部分中,还提供了代码示例:
interface ConstructorReference {
T constructor();
}
interface MethodReference {
void anotherMethod(String input);
}
public class ConstructorClass {
String value;
public ConstructorClass() {
value = "default";
}
public static void method(String input) {
System.out.println(input);
}
public void nextMethod(String input) {
// operations
}
public static void main(String... args) {
// constructor reference
ConstructorReference reference = ConstructorClass::new;
ConstructorClass cc = reference.constructor();
// static method reference
MethodReference mr = cc::method;
// object method reference
MethodReference mr2 = cc::nextMethod;
System.out.println(cc.value);
}
}
模板简介:该模板名称为【普通方法如何转换为?Math::maxstaticIntBinaryOperator】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【Java】栏目查找您需要的精美模板。