在十四篇中介绍过lambda表达式。lambda简化了我们的代码,根据上下文环境,以及语法条件简化了我们的代码。而方法引用语法的出现在lambda的表达式的基础上做出了进一步表达式。
我们的lambda的概要格式为(形式参数)->(代码块)。在简化操作的同时我们有时候也需要在lambda表达式进行调用方法。我们采用lambda调用的方法可能已经有了。这个方法可能存在我们的类中,或者接口中。于是我们可以采用方法引用来做进一步的简化。 简单的说,方法引用使用的是已经存在的方法使用。
举一个非常简单易懂的例子🍌
定义一个接口,接口中给出一个方法。
package method;
public interface Printable {
void printString(String s);
}
然后在测试类中使用
package method;
public class PrintableDemo {
public static void main(String[] args) {
usePrintable((String s)->{
System.out.println(s);
});
}
private static void usePrintable(Printable p)
{
p.printString("爱生活,爱java");
}
}
不错,这是一个标准的lambda表达式,当然你也可以去简化参数括号和大括号。 我们的这个lambda调用了System.out的println方法。
很明显这个方法本身就有提供,于是你可以这样去使用
usePrintable(System.out::println);
我么连参数啥的都不用写了。说实话,我一开始看到这样的写法觉得很离谱,但是这个是java8之后的新特性。支持这样的语法。::这个符号代表引用符。我们引用System.out的println方法,然后我们的lambda原来的参数类型和参数就直接传给这个方法去进行处理了。
为什么可以这样写,原因就是可以进行推导出来。可推导的就是可以进行省略的。这样其实和lambda类似。当然,这样的方法引用其实本身就是一个lambda表达式。
在这里我只是说明了这个引用的引出以及和一般的lambda区别的使用。具体的继续说明。 🌼
还是按照完整的代码来举例,不然,单行代码显得太突兀。
我们还是先定义一个接口,这样就好进行对比分析了。
package method;
public interface Converter {
int convert(String s);
}
测试类
package method;
public class ConverterDemo {
public static void main(String[] args) {
//使用lambda表达式
// useConverter((String s)->
// {
// return Integer.parseInt(s);
// });
//优化
useConverter(s->Integer.parseInt(s));
//引用类方法
useConverter(Integer::parseInt);
//lambda被类方法替代的时候,它的形式参数全部传递给静态方法作为参数
}
private static void useConverter(Converter c)
{
int number = c.convert("666");
System.out.println(number);
}
}
在这里我们引用了类Integer类的静态方法parseInt方法。传递解释,代码注释说的很明白了。
这样的实例方法还是和静态方法有区别的,虽然引用的时候格式十分相似。静态方法是被类所有的,我们可以直接通过类名去调用,但是实例方法只能通过实例对象去调用。不然是无法去调用。
❗实例化对象我们这样说,类本身是静态的,本身不会占用进程内存,但是在我们实例化的时候会使其拥有动态内存。面向对象的设计中,一般实例化就是为类创建对象的过程。
举个例子
创建一个接口
package method;
public interface MyString {
String mySubString(String s,int x,int y);
}
测试类的具体使用
package method;
public class MyStringDemo {
public static void main(String[] args) {
// useMyString((String s,int x,int y)->
// {
// return s.substring(x,y);
// });
// useMyString((s,x,y)->s.substring(x,y));
//引用类中实例方法
useMyString(String :: substring);
//lambda被类的实例方法替代的时候,第一个参数作为调用者,后面的参数全部传递给该方法作为参数
}
private static void useMyString(MyString my)
{
String s = my.mySubString("Hello", 2, 6);
System.out.println(s);
}
}
可以去查看一下源码,substring()方法没有被static修饰,所以不属于类方法,但是属于类对象。也就是实例方法。我们知道String类是一定进行了实例化了。
有时候我们需要用到某个类的方法,如果你创建对象的时候在你的当前类要用到这个方法,一般是需要实例化对象的,但是如果你不想给出具体的实例,只是想简单的引用。那么就可以根据特殊类进行引用。
其实还是和上面的很类似
我们定义一个接口
package method;
public interface pratice_ {
void compare(String s1,String s2);
}
测试类
package method;
import java.util.TreeMap;
import java.util.TreeSet;
public class Pratice {
public static void main(String[] args) {
usePratice((x,y)->{
int i = x.compareTo(y);
System.out.println(i);
});//lambda常规
usePratice(String::compareTo);//这样使用
}
private static void usePratice(pratice_ m)
{
m.compare("Hello","good");
}
}
引用构造方法是如何做的呢?我们可以这样。
我们定义一个类
package method;
public class Student {
private String name;
private int age;
public Student()
{
}
public Student(String name,int age)
{
this.age = age;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
定义一个接口
package method;
public interface StudentBUilder {
Student build(String name,int age);
}
定义一个测试类
package method;
public class StudentDemo {
public static void main(String[] args) {
// useStudentBuilder((String name,int age)->{
// Student s = new Student(name, age);
// return s;
// });
useStudentBuilder((name,age)->new Student(name,age));
useStudentBuilder(Student::new);//lambda被构造器替代,它的形式参数全部被传递给构造器作为参数
}
private static void useStudentBuilder(StudentBUilder sb)
{
Student s = sb.build("jgdabc", 11);
System.out.println(s.getName()+","+s.getAge());
}
}
❗可能这样太多的简化写法在一定程度上回造成代码的阅读性不是很好,特别是很难直观看到面向对象的特点。但是存在即合理。java8的新特性,改进一定是由原因的。希望自己之后可以弥补自己当前的一些肤浅的认识。