Java8 方法引用-Method References

时间:2021-02-02 05:33:35

前言

怎样更好的引入Java8中的方法引用呢?
我们首先看一下一个简单的例子:

        Consumer<String> con=(str)->System.out.println(str);
con.accept("我是消费型接口!");

这时候你应该知道这行代码输出的是:

我是消费型接口!

那么使用方法引用后的代码又是怎样的呢?

        Consumer<String> con=System.out::println;
con.accept("我是消费型接口!");

这样就使用了方法引用来输出传入的字符串,代码是不是简洁了一点?那么我们到底要怎样使用方法引用呢?

什么是方法引用?

因为我们的Lambda表达式可能仅仅调用一个已经存在的方法(如上面的System.out.println(str);),那么我们就允许通过方法名来引用这个已经存在的方法。被引用的方法要加上::
如上面的例子,我们在void accept(T t){/***/}方法里面只有一个System.out.println(str);方法。
然后System.outPrintStream这个类。
故可以写成Consumer<String> con=System.out::println;这样的形式。

方法引用的规则

要想使用方法引用还得满足这样的一个规则:
同样以上面的程序为例子:
accept方法的源码:

void accept(T t);

System.outprintln()方法的源码:

    public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}

可以发现这两个方法的返回值和参数是一样的!
所以说只有在他们的参数列表和返回值相同的时候才可以用方法引用,为了便于理解,看下图:
Java8 方法引用-Method References

方法引用的四种形式

类型 示例
引用对象的实例方法 Object::instanceMethodName
引用类的静态方法 ClassName::staticMethodName
引用类的实例方法 ClassName::methodName
引用构造方法 ClassName::new

接下来举例说明:

Step1:定义学生类

以下所有的举例都是基于该学生类:

//学生类
class Student{

private String stuName; //学生姓名
private Integer stuAge; //学生年龄
private Double stuGrade;//学生成绩

public Student(){} //无参构造函数
public Student(String stuName){ //只有一个参数的构造函数
this.stuName=stuName;
}
public Student(String stuName,Integer stuAge,Double stuGrade){ //含有全部参数的构造函数
this.stuAge=stuAge;
this.stuGrade=stuGrade;
this.stuName=stuName;
}

//一些 get,set,toString方法
public Integer getStuAge() {
return stuAge;
}


public void setStuAge(Integer stuAge) {
this.stuAge = stuAge;
}


public String getStuName() {
return stuName;
}


public void setStuName(String stuName) {
this.stuName = stuName;
}


public Double getStuGrade() {
return stuGrade;
}


public void setStuGrade(Double stuGrade) {
this.stuGrade = stuGrade;
}

@Override
public String toString() {
return "Student [stuAge=" + stuAge + ", stuName=" + stuName + ", stuGrade=" + stuGrade + "]";
}

}

Step2:引用对象的实例方法

        /**
* 输出学生的姓名
* */

Student stu=new Student("张三",18,85.0);
//Supplier<String> supp=()->stu.getStuName();[原来写法]
Supplier<String> supp=stu::getStuName; //[使用方法引用]
System.out.println(supp.get());

Step3:引用类的静态方法

        /**
* 比较数字的大小
* */

//Comparator<Integer> com=(x,y)->Integer.compare(x, y); [原来写法]
Comparator<Integer> com=Integer::compare; //[使用方法引用]
System.out.println(com.compare(1, 2));

Step4:引用类的实例方法

        /**
* 判断两个字符串是否相等
* */

// BiPredicate<String, String> biPre=(str1,str2)->str1.equals(str2); [原来写法]
BiPredicate<String, String> biPre=String::equals; //[使用方法引用]

System.out.println(biPre.test("aaa", "aaa"));

注意:test函数传入的两个参数str1str2,必须满足:

第一个实例(str1)调用方法
第二个实例(str2)作为参数传入方法
就像str1.equals(str2)

Step5:引用构造方法

如果不使用方法引用:

    @Test
public void TestConstructMethodReferences(){
//实例化一个对象
Supplier<Student> supp=()->new Student();
Student stu=supp.get();
System.out.println(stu==null); //输出 false
}

使用方法引用-不传参:

    @Test
public void TestConstructMethodReferences(){
/**
* 说明:
* 由于未传入参数,所以调用 无参构造函数
* 输出:
* Student [stuAge=null, stuName=null, stuGrade=null]
* */

Supplier<Student> supp=Student::new;
Student stu=supp.get();
System.out.println(stu);
}

使用方法引用-传入一个参数:

    @Test
public void TestConstructMethodReferences1(){
/**
* 说明:
* 传入一个参数姓名,故调用只有一个参数的构造函数
* 输出:
* Student [stuAge=null, stuName=张俊强, stuGrade=null]
* */

Function<String,Student> supp=Student::new;
Student stu=supp.apply("张俊强");
System.out.println(stu);
}

使用方法引用-传入所有参数:
这样多于两个参数的我们就得自己定义接口啦,这里就不再赘述啦!

上面是实例化一个对象,那么对于数组应该怎样构造呢?
如下代码实例化一个长度为10的数组:

    @Test
public void TestArray(){
Function<Integer,String[]> supp=String[]::new;
String[] array=supp.apply(10);
System.out.println(array.length); //输出 10
}

最后

以上就基本是全部关于Java8中方法引用的基础知识了!