话接上篇,在上篇《Java Lambda表达式简介及入门》中我们介绍了lambda表达式的一些基本用法,在基本用法里面有时候抽象方法的实现是直接调用另外的一个方法来实现的,比如下面的例子,对于这种情况,我么有可能使用方法的引用来简化代码。
Consumer<String> co = s -> System.out.println(s);
Function<String, Integer> 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<String> s1 = () -> "hello";
Supplier<String> s2 = () -> lambda02.put();
Supplier<String> s3 = lambda02::put;
System.out.println(s3.get());
//有参无返回值
Consumer<Integer> c1 = a -> System.out.println(a);
Consumer<Integer> c2 = a -> lambda02.fun(a);
Consumer<Integer> c3 = lambda02::fun;
c3.accept(999);
//有参有返回值
Function<String, Integer> f1 = s -> s.length();
Function<String, Integer> f2 = s -> lambda02.len(s);
Function<String, Integer> f3 = lambda02::len;
System.out.println(f3.apply("hello"));
}
}
执行结果:

Supplier<T>是无参有返回值的函数式接口,
17行抽象方法的实现中我们简单的返回一个“hello”字符串
18行有一个静态函数put正好可以满足我们的需求,直接调用该方法
19行,根据静态方法引用的含义,将其改为静态方法引用的写法,类名::staticMethod,即lambda02::put。
Consumer<T>和Function<T, R>的示例类似。
实例方法引用
实例方法引用的含义
如果函数式接口的实现恰好可以通过调用一个实例的实例方法来实现,那么就可以使用实例方法引用
语法: 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<String, Integer> f4 = this::len;
System.out.println(f4.apply("callthis"));
}
public static void main(String[] args) {
Supplier<String> s1 = () -> "hello";
Supplier<String> s2 = () -> new lambda03().put();
Supplier<String> s3 = new lambda03()::put;
System.out.println(s3.get());
Consumer<Integer> c1 = a -> System.out.println(a);
Consumer<Integer> c2 = a -> new lambda03().fun(a);
Consumer<Integer> c3 = new lambda03()::fun;
c3.accept(999);
lambda03 exam = new lambda03();
Function<String, Integer> f1 = s -> s.length();
Function<String, Integer> f2 = s -> exam.len(s);
Function<String, Integer> f3 = exam::len;
System.out.println(f3.apply("hello"));
exam.callthis();
}
}
执行结果:

实例方法引用和静态方法引用类似
21行抽象方法的实现中我们简单的返回一个“hello”字符串
22行有一个实例方法put正好可以满足我们的需求,可以调用实例对象的该方法
19行,根据实例方法引用的含义,将其改为实例方法引用的写法,inst::instMethod,即new lambda03()::put。
Consumer<T>和Function<T, R>的示例类似。
因为是实例对象,所以在实例方法中我们可以使用this和super,14~18行演示了this的用法。
对象方法引用
对象方法引用的含义
抽象方法的第一个参数类型刚好是实例方法的类型,抽象方法剩余的参数恰好可以当做实例方法的参数。如果函数式接口的实现能由上面说的实例方法调用来实现的话,那么就可以使用对象方法引用
语法: 类名::instMethod
对象方法引用示例
直接先上代码:
public class lambda04 {
public static void main(String[] args) {
Consumer<Foo> c1 = (Foo foo) -> new Foo().foo();
Consumer<Foo> c2 = Foo::foo;
c1.accept(new Foo());
c2.accept(new Foo());
BiConsumer<Foo, String> c3 = (foo, str) -> new Foo().foo2(str);
BiConsumer<Foo, String> c4 = Foo::foo2;
c3.accept(new Foo(), "hello");
c4.accept(new Foo(), "hello");
BiFunction<Foo, String, Integer> c5 = (foo, str) -> new Foo().foo3(str);
BiFunction<Foo, String, Integer> 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<T>这些是不能写成对象方法引用的。
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<T, U, R>的前两个泛型是参数类型,第三个是返回值类型。(foo, str) -> new Foo().foo3(str),第一个参数foo的类型是Foo,实例方法foo3()也是属于Foo类的,所以参数类型符合,除去第一个参数foo,还有一个String类型的参数,实例方法foo3正好也是需要一个String类型的入参,符合抽象方法剩余的参数恰好可以当做实例方法的参数。同时foo3的返回值类型也符合。
15行 根据语法规则,改为对象方法的引用,即Foo::foo3
构造方法引用
构造方法引用的含义
如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用
类名::new
构造方法引用示例
直接先上代码:
public class lambda05 {
public static void main(String[] args) {
//无参数有返回值
Supplier<Person> s1 = () -> new Person();
Supplier<Person> s2 = Person::new;
s1.get();
s2.get();
Supplier<Thread> S3 = Thread::new;
Supplier<List> s4 = ArrayList::new;
Supplier<Map> s5 = HashMap::new;
//有参数无返回值
Consumer<Integer> c1 = age -> new Person(age);
Consumer<Integer> c2 = Person::new;
c1.accept(20);
c2.accept(20);
//有参数有返回值
Function<String, Person> f1 = name -> new Person(name);
Function<String, Person> f2 = Person::new;
f1.apply("jack ma");
f2.apply("pony ma");
}
}
执行结果:

构造方法引用引用比较简单,根据代码很容易理解,就不再详细解释了。
网友评论