话接上篇,在上篇《Java Lambda表达式简介及入门》中我们介绍了lambda表达式的一些基本用法,在基本用法里面有时候抽象方法的实现是直接调用另外的一个方法来实现的,比如下面的例子,对于这种情况,我么有可能使用方法的引用来简化代码。
Consumer co = s -> System.out.println(s);
Function f = s -> s.length();
但是转换为方法的引用,将是本章的主要内容。
代码下载
什么是方法的引用
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法,方法引用提供了一种引用而不执行方法的方式,如果抽象方法的实现恰好可以使用调用另外一个方法来实现,就有可能可以使用方法引用
方法引用的分类
根据上表可知方法引用有四类,接下来会介绍一种类型的用法。
静态方法的引用
静态方法引用的含义
如果函数式接口的实现恰好可以通过调用一个静态方法来实现,那么就可以使用静态方法引用
语法: 类名::staticMethod
静态方法引用示例
直接先上代码:
public class lambda02 {
public static String put() {
return "hello";
}
public static void fun(Integer a) {
System.out.println(a);
}
public static Integer len(String str) {
return str.length();
}
public static void main(String[] args) {
//无参有返回值
Supplier s1 = () -> "hello";
Supplier s2 = () -> lambda02.put();
Supplier s3 = lambda02::put;
System.out.println(s3.get());
//有参无返回值
Consumer c1 = a -> System.out.println(a);
Consumer c2 = a -> lambda02.fun(a);
Consumer c3 = lambda02::fun;
c3.accept(999);
//有参有返回值
Function f1 = s -> s.length();
Function f2 = s -> lambda02.len(s);
Function f3 = lambda02::len;
System.out.println(f3.apply("hello"));
}
}
执行结果:
Supplier
17行抽象方法的实现中我们简单的返回一个“hello”字符串
18行有一个静态函数put正好可以满足我们的需求,直接调用该方法
19行,根据静态方法引用的含义,将其改为静态方法引用的写法,类名::staticMethod,即lambda02::put。
Consumer
实例方法引用
实例方法引用的含义
如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用
语法: inst::instMethod
实例方法引用示例
直接先上代码:
public class lambda03 {
public String put() {
return "hello";
}
public void fun(Integer a) {
System.out.println(a);
}
public Integer len(String str) {
return str.length();
}
public void callthis() {
System.out.println("call this");
Function f4 = this::len;
System.out.println(f4.apply("callthis"));
}
public static void main(String[] args) {
Supplier s1 = () -> "hello";
Supplier s2 = () -> new lambda03().put();
Supplier s3 = new lambda03()::put;
System.out.println(s3.get());
Consumer c1 = a -> System.out.println(a);
Consumer c2 = a -> new lambda03().fun(a);
Consumer c3 = new lambda03()::fun;
c3.accept(999);
lambda03 exam = new lambda03();
Function f1 = s -> s.length();
Function f2 = s -> exam.len(s);
Function f3 = exam::len;
System.out.println(f3.apply("hello"));
exam.callthis();
}
}
执行结果:
实例方法引用和静态方法引用类似
21行抽象方法的实现中我们简单的返回一个“hello”字符串
22行有一个实例方法put正好可以满足我们的需求,可以调用实例对象的该方法
19行,根据实例方法引用的含义,将其改为实例方法引用的写法,inst::instMethod,即new lambda03()::put。
Consumer
因为是实例对象,所以在实例方法中我们可以使用this和super,14~18行演示了this的用法。
对象方法引用
对象方法引用的含义
抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用
语法: 类名::instMethod
对象方法引用示例
直接先上代码:
public class lambda04 {
public static void main(String[] args) {
Consumer c1 = (Foo foo) -> new Foo().foo();
Consumer c2 = Foo::foo;
c1.accept(new Foo());
c2.accept(new Foo());
BiConsumer c3 = (foo, str) -> new Foo().foo2(str);
BiConsumer c4 = Foo::foo2;
c3.accept(new Foo(), "hello");
c4.accept(new Foo(), "hello");
BiFunction c5 = (foo, str) -> new Foo().foo3(str);
BiFunction c6 = Foo::foo3;
System.out.println(c5.apply(new Foo(), "LAMBDA"));
System.out.println(c6.apply(new Foo(), "LAMBDA"));
}
}
class Foo {
public void foo() {
System.out.println("invoke");
}
public void foo2(String str) {
System.out.println("invoke:" + str);
}
public Integer foo3(String str) {
return str.length();
}
}
执行结果:
对象方法引用相比前面两种方法引用复杂一些。根据其含义“抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数”,第一个参数的类型需要是实例方法的类型,除了限定了第一个参数的类型,同时意味着抽象方法如果没有参数,是没有办法写成对象方法引用,所以Runnable,Supplier
4行 (Foo foo) -> new Foo().foo(),第一个参数foo的类型是Foo,实例方法foo()也是属于Foo类的,所以参数类型符合,除去第一个参数foo,就没有其他参数,实例方法foo也正好也没有参数,符合抽象方法剩余的参数恰好可以当做实例方法的参数。
5行 根据语法规则,改为对象方法的引用,即Foo::foo
9行 (foo, str) -> new Foo().foo2(str),第一个参数foo的类型是Foo,实例方法foo2()也是属于Foo类的,所以参数类型符合,除去第一个参数foo,还有一个String类型的参数,实例方法foo2正好也是需要一个String类型的入参,符合抽象方法剩余的参数恰好可以当做实例方法的参数。
10行 根据语法规则,改为对象方法的引用,即Foo::foo2
14行 BiFunction
15行 根据语法规则,改为对象方法的引用,即Foo::foo3
构造方法引用
构造方法引用的含义
如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用
类名::new
构造方法引用示例
直接先上代码:
public class lambda05 {
public static void main(String[] args) {
//无参数有返回值
Supplier s1 = () -> new Person();
Supplier s2 = Person::new;
s1.get();
s2.get();
Supplier S3 = Thread::new;
Supplier s4 = ArrayList::new;
Supplier
执行结果:
构造方法引用引用比较简单,根据代码很容易理解,就不再详细解释了。