::被称为方法引用。它基本上是对单个方法的引用。也就是说,它通过名称引用一个现有的方法。
简短说明:
下面是一个引用静态方法的例子:
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可以像对象引用一样传递,并在需要时触发。事实上,它可以很容易地作为对象的“正常”方法的引用使用,就像静态方法一样。例如:
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);
以上是一个功能接口。为了充分理解::,理解功能接口也很重要。简单地说,函数式接口就是只有一个抽象方法的接口。
功能性接口的例子包括Runnable、Callable和ActionListener。
上面的函数是一个函数接口,只有一个方法:apply。它需要一个参数并产生一个结果。
::s很棒的原因是:
方法引用是与lambda表达式(…)具有相同处理方式的表达式,但它们不是提供方法体,而是通过名称引用现有方法。
例如,而不是写lambda体
Function<Double, Double> square = (Double x) -> x * x;
你可以简单地
Function<Double, Double> square = Hey::square;
在运行时,这两个平方方法的行为完全相同。字节码可以是相同的,也可以不是相同的(尽管,对于上面的情况,生成了相同的字节码;编译上面的代码并用javap -c检查)。
唯一需要满足的主要标准是:您提供的方法应该与用作对象引用的函数接口的方法具有类似的签名。
以下内容是非法的:
Supplier<Boolean> p = Hey::square; // illegal
Square需要参数并返回double。Supplier中的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;
方法引用可以有不同的风格,但基本上它们都意味着相同的事情,可以简单地可视化为lambdas:
一个静态方法(ClassName::methName)
特定对象的实例方法(instanceRef::methName)
特定对象的超方法(super::methName)
特定类型的任意对象的实例方法(ClassName::methName)
类构造函数引用(ClassName::new)
数组构造函数引用(TypeName[]::new)
有关进一步参考,请参阅Lambda的状态。