基本使用
冗余的Lambda场景
- 1 定义一个函数式接口
//定义打印的函数式接口
@FunctionalInterface
public interface Printable {
//打印字符串的抽象方法
void print(String s);
}
- 2 使用
- 分析:
其中 printString 方法只管调用 Printable 接口的 print 方法,而并不管 print 方法的具体实现逻辑会将字符串打印到什么地方去。而 main 方法通过Lambda表达式*指定了函数式接口 Printable 的具体操作方案为:拿到String数据后,在控制台中输出它。 - 方法引用
1 双冒号 :: 为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。
2 现成的实现: System.out对象中的 println(String) 方法。
Lambda希望做的事情就是调用 println(String) 方法
- 注意::Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型,否则会抛出异常
- 分析:
public class D01Printable {
//定义一个方法,参数传递Printable接口,对字符串进行打印
public static void printString(Printable p) {
p.print("Helloworld"); //传入s参数“Helloworld”
}
public static void main(String[] args) {
//调用Printable方法,方法的参数是一个函数式接口,可以传递Lambda
//1 拿到参数之后经Lambda之手,继而传递给 System.out.println 方法去处理。
printString((s)->System.out.println(s));
/*
分析:
Lambda表达式的目的:打印参数传递的字符串
把参数s传递给System.out对象,调用out对象中的方法println对字符串进行输出
注意:
1 System.out对象是已经存在的
2 println方法也是已经存在的
所以我们可以使用引用方法来优化Lambda表达式
可以使用System.out方法之间引用(调用)println方法
*/
//2 直接让 System.out 中的 println 方法来取代Lambda
printString(System.out::println); //::方法引用
}
}
1 通过对象名引用成员方法
- 使用前提:
方法引用的使用前提是引用的对象是已经存在的,方法也是已经存在的,就可以使用对象来引用方法,进而优化Lambda
public class D02TestMethodTerObj {
//定义一个方法,方法的参数传递之前定义的Printable接口
public static void printString(Printable p) {
p.print("Hello");
}
public static void main(String[] args) {
//调用Printable方法,方法的参数是一个函数式接口,可以传递Lambda
printString((s)->{
//具体的实现:不直接打印,而是调用类的成员方法
//创建MethodRerObject对象
D02MethodRerObject obj = new D02MethodRerObject();
//调用MethodRerObject对象中的成员方法printUpperCaseString,把字符串按大写打印
obj.printUpperCaseString(s); //HELLO
});
/*
使用方法引用优化Lambda:
对象是一次存在的D02MethodRerObject
成员方法也是已经存在的printUpperCaseString
所以我们可以使用对象名来引用成员方法
*/
D02MethodRerObject obj = new D02MethodRerObject();
printString(obj::printUpperCaseString);
}
}
2 通过类名引用静态方法
类已经存在,静态成员方法也已经存在,就可以通过类名直接引用静态方法
//定义一个计算的函数式接口
@FunctionalInterface
public interface Calcable {
//定义一个抽象方法,对整数进行绝对值计算
int calAbs(int num);
}
public class D03StaticMeRer {
//定义一个方法,方法的参数传递要计算的整数和函数式接口
public static int method(int num,Calcable c) {
return c.calAbs(num);
}
public static void main(String[] args) {
int number = method(-10, (n)->{
//对参数进行绝对值计算,并返回计算结果
return Math.abs(n);
});
System.out.println(number); //10
/*
使用方法引用优化Lambda
Math类是存在的,abs方法也是存在的,可以直接类名调用静态方法
*/
int num2 = method(-10, Math::abs);
System.out.println(num2); //10
}
}
3 通过super引用成员方法
如果存在继承关系,当Lambda中需要出现super调用时,也可以使用方法引用进行替代。
- Lambda表达式: () -> super.sayHello()
- 方法引用: super::sayHello
//定义一个函数式接口
public interface Greetable {
void greet(); //定义一个见面的方法
}
//定义父类
public class D04Human {
//定义一个sayHello的方法
public void sayHello() {
System.out.println("Hello,我是Human");
}
}
//子类
public class D04Man extends D04Human {
//重写父类方法
@Override
public void sayHello() {
System.out.println("Hello,我是man");
}
//定义一个方法,参数传递Greetable接口
public void method(Greetable g) {
g.greet();
}
public void show() {
//调用method方法,方法的参数Greetable是一个函数式接口,所以可以传递Lambda
/*
method(()->{
//创建父类对象
D04Human h = new D04Human();
//调用父类方法
h.sayHello();
});
*/
//因为有子父类关系,所以存在关键字super,代表父类,我们可以直接使用super调用父类的成员方法
method(()->super.sayHello());
//使用super引用父类成员方法,父类存在,父类成员方法已存在
method(super::sayHello);
}
//主类:执行
public static void main(String[] args) {
new D04Man().show(); //Hello,我是Human
}
}
4 通过this引用成员方法
this代表当前对象,如果需要引用的方法就是当前类中的成员方法,那么可以使用“this::成员方法”的格式来使用方法引用。
//定义一个富有的函数式接口
@FunctionalInterface
public interface Richable {
//定义一个想买什么就买什么的方法
void buy();
}
//通过this引用本类成员方法
public class D05Husband {
//定义一个买房子的方法
public void buyHouse() {
System.out.println("北京二环内买一套四合院");
}
//定义一个结婚的方法,参数传递Richable接口
public void marry(Richable r) {
r.buy();
}
//定义一个非常高兴的方法
public void sayHello() {
//调用结婚的方法,方法的参数是一个函数式接口,传递;Lambda
/*
marry(()->{
this.buyHouse(); //this调用本类买房子的方法
});
*/
marry(this::buyHouse);
}
/*
使用方法引用优化Lambda表达式
this是已经存在的,本类的成员方法buyHouse也是已经存在的
我们可以直接this引用本类成员方法
*/
public static void main(String[] args) {
new D05Husband().sayHello(); //北京二环内买一套四合院
}
}
4 类的构造器引用
由于构造器的名称与类名完全一样,并不固定。所以构造器引用使用 类名称::new 的格式表示
//创建一个Person类
public class D06Person {
private String name;
public D06Person() {
super();
}
public D06Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//定义一个创建Person对象的函数式接口
@FunctionalInterface
public interface PersonBuilder {
//定义一个方法,根据传递的姓名,创建Person对象返回
D06Person builPerson(String name);
}
public class D06TestPerson {
//定义一个方法,参数传递姓名和PersonBuilder接口,方法中通过姓名创建Person对象
public static void printName(String name,PersonBuilder p) {
D06Person person = p.builPerson(name);
System.out.println(person.getName());
}
public static void main(String[] args) {
//调用printName方法,参数PersonBuilder是函数式接口,传递Lambda表达式
printName("泡泡", (String name)->{
return new D06Person(name); //泡泡
});
/*
使用方法引用,优化Lambda表达式
构造方法new Person(String name)已知
创建对象已知,new
就可以使用Person引用new创建对象
*/
printName("战战", D06Person::new); //其实就是调用Person类有参构造方法,通过传递的姓名创建对象
}
}
5 数组的构造器引用
数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同
//定义一个创建数组函数式接口
@FunctionalInterface
public interface ArrayBuilder {
//定义一个创建Int类型的数组的方法,参数传递数组的长度,返回创建好的int类型数组
int[] builderArray(int length);
}
/*
数组的构造器引用
*/
public class D07Shuzu {
/*
定义一个方法,方法的参数传递创建数组的长度和ArrayBuilder接口
方法内部根据传递的长度使用ArrayBuilder中的方法builderArray创建数组并返回
*/
public static int[] createArray(int len,ArrayBuilder ab) {
return ab.builderArray(len);
}
public static void main(String[] args) {
//调用createArray方法,传递数组长度和Lambda表达式
int[] array = createArray(10,(len)->{
return new int[len];
});
/*
使用方法引用优化Lambda
已知创建的是int[] 数组
数组的长度已知
就可以使用方法引用
int[] 引用new,根据参数传递的长度来创建数组
*/
int[] array2 = createArray(10, int[]::new);
System.out.println(array.length); //10
System.out.println(array2.length); //10
System.out.println(Arrays.toString(array2)); //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}