1.函数方法
如果接口只有一个方法,则可以为该接口类型的变量分配一个由lambda 表达式(lambda 函数)给出的值。这样的接口被称为功能接口(在 Java 添加对 lambda 函数的支持之后)。
例如,Java 有Consumer<Type>
接口,接口有accept(Type obj)
方法。为什么需要这个接口?
在 Java 8 中,集合有一个forEach()
方法,可以让你对集合中的每个元素执行一些操作 。这里的功能接口用于将操作传递给方法。 Consumer<T>
forEach()
以下是显示集合的所有元素的方法:
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Hello", "how's", "life?");
list.forEach( (s) -> System.out.println(s) );
编译器会将上面的代码转换为下面的代码:
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Hello", "how's", "life?");
list.forEach(new Consumer<String>()
{
public void accept(String s)
{
System.out.println(s));
}
});
第一个版本肯定比第二个版本短。虽然带有 lambda 表达式的代码难以阅读,但带有匿名内部类的代码有时更难阅读。
2、方法参考
然而,我们的lambda 表达式代码可以写得更短。
首先,您可以省略参数周围的括号s
:
list.forEach( (s) -> System.out.println(s) );
list.forEach( s -> System.out.println(s) );
这只有在只有一个参数的情况下才能完成。如果有多个参数,则必须使用括号。
其次,你可以这样写:
list.forEach( System.out::println );
这是完全相同的符号。请注意,在 . 之后没有括号println
。
这里我们有相同的代码——一个方法调用:
object::method
x -> object.method(x)
想一想:我们想对list
集合中的每个元素执行一些操作。如果操作是单个函数调用(例如println()
),那么将函数作为参数简单地传递给方法是有意义的。
但是我们如何向编译器解释我们要传递方法而不是调用它呢?为此,我们在方法名称前使用了两个冒号,而不是点运算符。单个冒号已用于指示三元运算符。
这是最简单和最紧凑的表示法。
3.构造函数
当我们使用 I/O 流时,使用双冒号的方法引用非常方便。稍后你会看到这个。
同时,让我们谈谈传递方法引用的 3 种流行方式:
引用对象的方法
要传递对对象方法的引用,您需要编写类似. 此代码等效于.object::method
x -> object.method(x)
特殊this
和super
变量可以用作对象。
引用类的方法
要传递对静态方法的引用,您需要编写类似. 此代码被转换为类似的代码class::method
x -> class.method(x);
引用构造函数
构造函数的行为类似于静态类方法,因此您也可以将引用传递给构造函数。这是它的样子:class::new
例如,您可以绕过集合的类型擦除并将方法传递toArray()
给将创建所需数组的构造函数的引用:toArray(int[]::new);
GO TO FULL VERSION