在使用Lambda表达式的时候,实际我们传递的是一段解决问题的代码。给什么参数做什么操作
Lambda冗余的场景
比如想要打印一个文件内容。
@FunctionalInterface
interface A{
//定义唯一一个抽象方法
void b(String string);
}
准备一个测试类:
public class DemoMethod {
public static void main(String[] args) {
name2();
}
//定义一个静态的方法,方法的参数传递一个函数式接口,
public static void name(A a) {
a.b("hahahah");
}
public static void name2() {
//传统的Lambda表达式写法
// name(string->{
// Demo02 sDemo02=new Demo02();
// sDemo02.name1(string);//Demo02.name(string)
// });
/*
* 使用方法引用优化Lambda
* 1.对象已经是存在的sDemo02
* 2.成员方法也是已经存在的name
* 3.所以我们就可以使用对象的方法引用。
*/
//首先对象必须已经存在
Demo02 sDemo02=new Demo02();
name(sDemo02::name1);
//打印流已經確定
PrintStream printStream=System.out;
//通过对象来引用对应的成员方法
name(printStream::println);
}
}
在测试类中,定义一个静态方法,静态方法传递一个函数式接口PrintStream,函数式接口当中定义了唯一一个抽象方法print,这就是print方法接收一个字符串参数,目的就是为了打印接收的字符串参数,通常我们可以使用Lambda表达式来实现以上需求。
但是经过我们观察,对字符串进行控制台打印输出的操作方案,明明已经有了现成的执行方案,System.out对象中有一个方法println(String str),所以我们可以直接通过对象名来引用该方法println来实现在控制台打印输出字符串内容。
//打印流已經確定
PrintStream printStream=System.out;
//通过对象来引用对应的成员方法
name(printStream::println);
注意:其中的双冒号::写法,被称之为“方法引用”,两个冒号是一种新语法。
方法引用符号
双冒号::也被归置为引用运算符,
使用方法引用的使用场景:
通过对象名引用成员方法
//先准备一个类,类中需要定义一个成员方法
class Demo02{
//定义一个成员方法,传递一个字符串,把字符串转换为大写输出
public void name1(String string) {
System.out.println(string.toUpperCase());
}
}
//准备一个函数式接口
interface A{
//定义唯一一个抽象方法
void b(String string);
}
//定义一个测试类
public class DemoMethod {
public static void main(String[] args) {
name2();
}
//定义一个静态的方法,方法的参数传递一个函数式接口,
public static void name(A a) {
a.b("hahahah");
}
public static void name2() {
/*
* 使用方法引用优化Lambda
* 1.对象已经是存在的sDemo02
* 2.成员方法也是已经存在的name
* 3.所以我们就可以使用对象的方法引用。
*/
//首先对象必须已经存在
Demo02 sDemo02=new Demo02();
name(sDemo02::name1);
//打印流已經確定
PrintStream printStream=System.out;
//通过对象来引用对应的成员方法
name(printStream::println);
}
}
通过类名来引用静态方法
比如java.lang.Math存放的都是静态方法,
//定义一个测试类
public class DemoStaticMethod {
public static void main(String[] args) {
demostatic();
}
//定义一个静态方法,该方法中传递一个函数式接口,再次传递一个浮点数
public static double name(Double b,DemoStatic demoMethod) {
return demoMethod.demo(b);
}
public static void demostatic() {
double num=name(-3.14, d->{
return Math.abs(d);
});
System.out.println(num);
/*
* 使用方法引用进行方法优化
* 首先类名已经确定
* 类中定义的静态方法是已经确定的
* 使用类名引用类中的静态方法
*
*/
double num2=name(-4.14,Math::abs);
System.out.println(num2);
}
}
//定义一个函数式接口
@FunctionalInterface
interface DemoStatic {
double demo(double b);
}
备注:Lambda表达式写法:d->Math.abs(d)
方法引用写法:Math::abs
这两种写法是等价的。
通过super来引用成员方法
如果存在继承关系,当Lambda中需要使用super调用时,也可以使用方法引用来优化Lanbda表达式.
//定义一个父类
class Animal{
//定义一个成员方法 交流的方法
public void talk() {
System.out.println("我是动物");
}
}
//定义一个子类
public class Cat extends Animal{
@Override
public void talk() {
System.out.println("我是小猫");
}
//定义一个方法 方法的参数传递一个函数式接口
public static void name(Meet meet) {
meet.meet();
}
//定义一个成员方法 沟通的方法
public void commu() {
System.out.println("11111111");
//传统的Lambda表达式写法
name(()->{
//创建父类的对象
//创建父类的方法
Animal animal=new Animal();
animal.talk();
});
System.out.println("2222222");
//使用super当中的方法,直接用super来调用
name(()->super.talk());
/*
* 使用super关键字来引用成员方法
* super已经存在
* 父类当中的成员方法talk已经存在的
* 可以使用super引用父类当中的成员方法
*/
System.out.println("33333");
name(super::talk);
}
public static void main(String[] args) {
Cat cat = new Cat();
cat.commu();
}
}
@FunctionalInterface
interface Meet{
//定义一个抽象方法 见面的抽象方法
void meet();
}
通过this来引用本类中当中的成员方法:
this指代当前对象,如果需要引用的方法就是本类当中的成员方法,那么可以使用this::成员方法来优化Lambda表达式
//定义一个类
public class DemoThis {
//定义一个成员方法,方法的参数传递一个函数式接口study
public void name(Demo demothis) {
demothis.learn();
}
//定义一个成员方法 happy
public void toHappy() {
name(()->System.out.println("去学习吧,使你快乐"));
name(()->{
DemoThis demoThis=new DemoThis();
demoThis.work();
});
//使用this优化Lambda表达式
name(this::work);
}
//定义一个work方法
public void work() {
System.out.println("学习");
}
}
@FunctionalInterface
interface Demo{
//定义一个学习的抽象方法
void learn();
}
类的构造器引用:
//定义一个类
public class DemoClass {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "DemoClass [name=" + name + "]";
}
public DemoClass(String name) {
// super();
this.name = name;
}
public DemoClass() {
// super();
}
public static void name(String name,Ddemo) {
System.out.println(demo.demo(name).getName());
}
public static void main(String[] args) {
name("hahah", name->new DemoClass(name));
name("jjjj",DemoClass::new);
}
}
//定以一个函数式接口
@FunctionalInterface
interface D{
DemoClass demo(String name);
}
数组构造器引用:
数组也是object 的子类对象,所以同样具有构造器,只不过语法稍微有点区别。
public class DemoArray {
//
public static int[] name(int length, M m) {
return m.Demo(length);
}
public static void main(String[] args) {
//Lambda表达式操作
int[] name = name(10, length -> new int[length]);
System.out.println(name.length);
//方法引用引用操作
int[] name2 = name(20, int[]::new);
System.out.println(name2.length);
/*
*
* 这两个写法是等价的
*/
}
}
@FunctionalInterface
interface M {
//定义一个函数式接口
int[] Demo(int length);
}
为什么?
推导和省略
如果使用Lambda,那么根据“可推导就可以省略原则”,无须指定参数类型,也无需指定的重写的形式-->它们都可以被推导出来,所以就可以省略掉,能够使用方法引用,同样也是可以根据上下文进行推导。
函数时接口是Lambda表达式的基础,而方法引用是Lambda的优化品。