版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
继JDK 1.8之后,更新了lambda的新特性
lambda是一种强调做什么,而不是用什么去做的语法
而匿名内部类则是强调如何去做,用了什么去做这件事的语法
函数式接口:有且仅有一个抽象方法的接口,就叫函数式接口
常用@FunctionalInterface标签标示
@FunctionalInterface
public interface test{
public void run();
}
lambda表达式的前提,就是要使用函数式接口使用
比如:函数式接口作方法参数,函数式接口作方法返回值,函数式接口创建实现类对象时可以使用
格式:(抽象方法的参数)->{抽放方法的方法体};
!!若抽象方法参数仅有一个时可以省略括号()
!!若抽象方法的方法体只有一条时,可以省略大括号{}和return;
作个简单例子:
@FunctionalInterface
interface test {
public void run(String string);
}
public class blog {
public static void main(String[] args) {
test t1 = new test() {
@Override
public void run(String string) {
System.out.println("匿名内部类创建实现类对象" + string);
}
};
test t2 = (string) -> {
System.out.println("lambda创建实现类对象" + string);
};
}
}
这就是lambda表达式与匿名内部类的区别:
匿名内部类需要写抽象方法的方法名等内容
而lambda只要写清抽象方法的参数和方法体即可
由于上面的t2实现类中只传入一个参数所以小括号可以取消,方法体只有一条语句,大括号可以取消
写成如下形式:
test t = string-> System.out.println(string);
方法引用:
创建了函数式接口的匿名内部类对象
重写了函数式接口的抽象方法并在重写的方法中调用被引用的方法
通俗的说,就是用lambda创建了函数式接口的实现类对象,正好lambda要写的抽象体是其他方法的方法体
1.静态方法引用
格式 :
类名::方法名
注意事项:
被引用的方法参数列表和函数式接口中抽象方法的参数一致!!
接口的抽象方法没有返回值,引用的方法可以有返回值也可以没有
接口的抽象方法有返回值,引用的方法必须有相同类型的返回值!!
interface test {
public void run(String string);
}
public class blog {
public static void main(String[] args) {
printString("静态方法引用",System.out::println);
// 实质代码: printString("静态方法引用", (string) -> System.out.println(string));
}
public static void printString(String str, test t) {
t.run(str);
}
}
这个代码中,利用lambda表达式创建了test接口的实现类对象,
重写run()方法,正好方法体是静态方法printString方法
稍微修改一下,将函数式接口抽象方法作为一个有返回值的方法,那么引用方法也得有同样类型的返回值
interface test {
public int run(String string);
}
public class blog {
public static void main(String[] args) {
// 实质代码: getInteger("123", (str) -> Integer.parseInt(str));
int i = getInteger("123", Integer::parseInt);
System.out.println(i); //输出:123
}
public static int getInteger(String str, test t) {
return t.run(str);
}
}
两个例子中,分别调用System.out类的println静态方法,Integer类的parseInt静态方法
由于满足抽象参数列表与引用参数列表相同,所以可以写成静态方法引用的格式
2.对象方法引用
格式:
对象名::非静态方法名
注意事项与静态方法引用完全一致
@FunctionalInterface
interface test {
public String run(String string);
}
class Person {
public String goWalking(String string) {
return string.concat(" 引用方法");
}
}
public class blog {
public static void main(String[] args) {
//实质代码: test t1 = (string) -> new Person().goWalking(string);
//实质代码: System.out.println(t1.run("对象"));
test t2 = new Person()::goWalking;
System.out.println(t2.run("对象")); //输出:对象 引用方法
}
}
类中有一个方法goWalking()方法体是test实现类对象需要的方法体
且方法列表参数一致,返回值类型相同
则可以利用lambda创建test的实现类对象,然后重写的抽象方法体就是调用Person对象的goWalking方法
符合对象引用方法的所有要求,则可以写成t2的样式
3.构造方法引用
格式:
类名::new
注意事项:
被引用的类必须存在一个构造方法与函数式接口的抽象方法参数列表一致
interface test {
public Person1 run(String string);
}
class Person {
String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class blog {
public static void main(String[] args) {
//实质代码: test t1 = (string) -> new Person(string);
//实质代码: Person p = t1.run("张三");
test t2 = Person::new;
Person p2 = t2.run("李四");
System.out.println(p2); //输出:Person{name='李四'}
}
}
由于函数式接口test中抽象方法,返回值是Person对象,且参数列表与Person类中的构造方法相同
则可以通过创建函数式接口的实现类对象,方法体通过调用类中的构造方法创建对象
使用了构造方法引用写成了代码中t2的形式
4.数组构造方法引用
格式:
数据类型[ ]::new
interface test {
public String[] run(int length);
}
public class blog {
public static void main(String[] args) {
//实质代码: test t1 = (length) -> new String[length];
test t2 = String[]::new;
String[] arr = t2.run(5);
}
}
5.特定类型的方法引用
格式:
类名::非静态方法
public class blog {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"d1wdaddq","ASDINAOSDN","aa","AA");
//实质代码: Collections.sort(list,(string1,string2)->string1.compareToIgnoreCase(string2));
Collections.sort(list,String::compareToIgnoreCase);
System.out.println(list);
}
}
特定类型方法引用,在Comparator函数式接口的抽象方法中传入的参数有两个,
可是compareToIgnoreCase()方法参数只有一个,第一个传入的参数作调用对象
这就满足了特定类型的方法引用,所以可以简化成类名::非静态方法的形式
6.类中方法调用父类或本类方法引用
格式:
this::方法名
super::方法名
interface test {
public void itMethod();
}
class father {
public void buy() {
System.out.println("买东西");
}
}
class son extends father {
public void buy() {
System.out.println("买糖");
}
public void test() {
// 实质代码: test t = () -> buy();
test t = this::buy;
t.itMethod();
// 实质代码: test t2 = ()->super.buy();
test t2 = super::buy;
t2.itMethod();
}
}
public class blog {
public static void main(String[] args) {
son s = new son();
s.test(); //输出: 买糖 买东西
}
}
在有继承关系的类中,若方法想调用本类或父类的成员方法
在函数式接口抽象方法与成员方法参数列表相同,且返回值类型相同的情况下
也可以使用this和super的方法引用来简写原本的lambda代码