在上一篇λ表达式的文章中有提到,一个接口未实现方法,有3种途径可以使用,实际上还有一种途径可以使用,也就是java8推出的::,这个是什么呢,就叫它方法引用吧。来看下是怎么操作的先。比如有一个与接口毫无关联的类Third,代码如下
package help.mygod.java8;
public class Third {
public String getNameById(String id){
if("003".equals(id)){
return "xiao san";
}else {
return "normal";
}
}
}
然后我正在一边使用接口开发,我的接口是这样子的
package help.mygod.java8;
@FunctionalInterface
public interface IStudent {
String getName(String id);
default void printName(){
System.out.println("I student");
}
}
我准备用λ表达式来实现这个方法,大概就是如果学号是003的,那她就是小三,其它的就是正常的,好吧,这个应该很快写出来,但我一看,旁边有个毫无关联类的方法正好和我想写的方法一样,入参,返回参数都匹配,虽然方法名不一样,那我能不能直接用它呢,答案是可以的。如下
package help.mygod.java8;
public class Main {
public static void main(String[] args) {
// 3,λ表达式
printName(id -> {
if ("007".equals(id))
return "William";
else
return "Moss";
}, "007");
Third t = new Third();
//4,别人家的方法
printName(t::getNameById, "007");
}
public static void printName(IStudent student, String id) {
System.out.println(student.getName(id));
}
}
看到了吧。只要入参和出参一样,方法就可以到处引用。这个和方法调用差不多,静态的前面可以用类名,非静态则前面是用实例名。所以这个就是方法引用。很多人会混淆引用和调用。引用就是把方法内容传过去,调用就是执行方法,得到结果了。
然后,不知道大家注意了到了没有,无论是λ表达式还是::,方法名都显得无关紧要了,入参和出参才是最重要的。 我这边还有一个接口,大概是想实现通过小孩的名称而找到父亲的名称,代码如下
package help.mygod.java8;
public interface IKingdom {
String getFatherName(String childName);
}
然后调用客户端的代码如下:
package help.mygod.java8;
public class Main {
public static void main(String[] args) {
// 3,λ表达式
printName(id -> {
if ("007".equals(id))
return "William";
else
return "Moss";
}, "007");
Third t = new Third();
//4,别人家的方法
printName(t::getNameById, "007");
//通过小孩姓名找父亲姓名
printFatherName(childName -> {
if("xiaoming".equals(childName))
return "daming";
else
return "dahong";
},"xiaoming");
}
public static void printName(IStudent student, String id) {
System.out.println(student.getName(id));
}
public static void printFatherName(IKingdom kingdom, String childName) {
System.out.println(kingdom.getFatherName(childName));
}
}
如果还有很多类似的方法,通过传入一个String,又返回一个String的,是不是有很多大量类似的代码呢。既然方法名又不重要,为什么不起一些通用的名字,而大家都用一个接口呢,所以方法改造如下,先是接口
package help.mygod.java8;
public interface ICommon <T> {
T getName(T t);
}
调用代码如下:
package help.mygod.java8;
public class Main {
public static void main(String[] args) {
// 3,λ表达式
printName(id -> {
if ("007".equals(id))
return "William";
else
return "Moss";
}, "007");
getName(id -> {
if ("007".equals(id))
return "William";
else
return "Moss";
}, "007");
Third t = new Third();
//4,别人家的方法
printName(t::getNameById, "007");
//通过小孩姓名找父亲姓名
printFatherName(childName -> {
if("xiaoming".equals(childName))
return "daming";
else
return "dahong";
},"xiaoming");
getName(childName -> {
if("xiaoming".equals(childName))
return "daming";
else
return "dahong";
},"xiaoming");
}
public static void printName(IStudent student, String id) {
System.out.println(student.getName(id));
}
public static void printFatherName(IKingdom kingdom, String childName) {
System.out.println(kingdom.getFatherName(childName));
}
public static void getName(ICommon common,String key){
System.out.println(common.getName(key));
}
}
哈哈,看到了吧。getName执行的结果是一样的。所以java8可以根据入参和出参就能封装。可以省略很多代码。所以,同学们,开始封装吧,哦,等等。因为这封装也太显眼了,所以java8说,干脆我替你们封装吧。所以就根据入参和出参封装了一系列常用的接口,也叫默认函数式接口吧。这里就列举一些常用的,大家要用的时候就查吧。
Predicate 接口只有一个参数,返回boolean类型。
Function 接口有一个参数并且返回一个结果。
Supplier 接口返回一个任意范型的值,和Function接口不同的是该接口没有任何参数。
Consumer 接口表示执行在单个参数上的操作。
。。。。。。