Java中的函数式编程Lambda、方法引用详解
引入
函数式编程中“函数”类似于数学中的函数(强调做什么),只要输入的数据一致返回的结果也是一致的

函数式编程解决了什么问题?什么是函数式编程?
使用Lambda函数替代吗某些匿名内部类对象,从而让程序代码更简洁,可读性更好。
一:Lambda
1、认识Lambda表达式
- JDK8开始新增的一种语法形式,它表示函数。
- 可以用于替代匿名内部类对象,从而让程序更简洁,可读性更好。
- 注意:Lambda表达式只能替代函数式接口的匿名内部类!!!!。
什么是函数式接口
- 有且仅有一个抽象方法的接口。
思考:为什么只能替代函数式接口的匿名内部类,分析:函数式接口只能有一个抽象方法,在简化的时候,会找到这个抽象方法并为这个方法重写。如果有多个抽象方法,简化后:编译器不知道要为那个抽象方法重写。
Lambda表达式的书写格式
(参数列表) -> { 表达式或语句块 }(参数列表):定义 Lambda 表达式接受的参数。参数的类型通常可以由编译器推断,因此可以省略。->:称为 Lambda 操作符 或 箭头操作符。它将参数列表与 Lambda 主体分隔开。{ 表达式或语句块 }:Lambda 表达式的主体,包含要执行的代码。- 如果表达式或语句块:只有一句{ }可以省略,否则不可省略。
Test类:代码1演示了:注意:Lambda表达式只能替代函数式接口的匿名内部类!!!!。
public class Test {
public static void main(String[] args) {
System.out.println("______________抽象类的匿名内部类_____________");
Animal animal = new Animal() {
@Override
public void cry() {
System.out.println("猫喵喵喵~~");
}
};
animal.cry();
System.out.println("______________简化抽象类的匿名内部类(报错)_____________");
//Lambda简化匿名内部类
//下面代码出错,Lambda表达式只能替代函数式接口的匿名内部类!!!!。
// Animal animal = ()->{
// System.out.println("猫喵喵喵~~");
// };
System.out.println("______________接口的匿名内部类_____________");
Swim s = new Swim() {
@Override
public void swiming() {
System.out.println("狗游游游~~");
}
};//分号不能忘
s.swiming();
System.out.println("______________简化函数式接口的匿名内部类_____________");
Swim s1 = () -> {
System.out.println("狗游游游~~");
};
s1.swiming();
}
}
//动物类
abstract class Animal {
abstract void cry();
}
//写一个游泳接口
@FunctionalInterface //声明函数式接口 ,函数式接口只能有一个抽象方法,
// 如果有多个抽象方法,使用注解声明后会报错
interface Swim {
void swiming();
}
/*
输出:
______________抽象类的匿名内部类_____________
猫喵喵喵~~
______________简化抽象类的匿名内部类(报错)_____________
______________接口的匿名内部类_____________
狗游游游~~
______________简化函数式接口的匿名内部类_____________
狗游游游~~
*/2、Lambda实战实例、省略规则
1.使用Lambda简化comparator接口的匿名内部类

2.Lambda表达式的省略规则
作用:用于进一步简化Lambda表达式写法。
具体规则:
- 参数类型全部可以省略不写。
- 如果只有一个参数,参数类型省略的同时“()”也可以省略,但是对个参数不能省略“()”。
- 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号“;” 如果这行代码是return语句,也必须去掉return。
代码2:下面是comparator接口sort对学生对象排序的代码简化过程。在上篇文章匿名内部类中给过这个代码的完整版本。
// Arrays.sort( s, new Comparator<Student>() {
// @Override
// public int compare(Student o1, Student o2) {
// return o1.getAge() - o2.getAge();
// }
// });
// Arrays.sort( s, (Student o1, Student o2) -> {
// return o1.getAge() - o2.getAge();
// });
// Arrays.sort( s, ( o1, o2) -> {
// return o1.getAge() - o2.getAge();
// });
Arrays.sort( s, ( o1, o2) -> o1.getAge() - o2.getAge());二、方法引用
1、静态方法引用
静态方法引用(Static Method Reference) 是一种特殊的语法,用于直接引用一个类的静态方法,并将其作为函数式接口的实例。它是 Lambda 表达式的更简洁替代形式。
语法:
类名::静态方法名
类名: 定义了静态方法的类的名称。::方法引用操作符。静态方法名: 要引用的静态方法的名称,不带括号()和参数。
使用场景
如果某个Lambda表达式里只是调用一个静态方法,并且“—>”前后参数的形式一致,(就像是下面的例子,->两边都是o1、o2)就可以使用静态方法引用。
代码3:下面代码演示了静态方法引用的使用场景
Student 类
public class Student {
private String name;
private int age;
//构造器
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//静态 方法引用
public static int compare(Student o1, Student o2){
return o1.getAge() - o2.getAge();
}
}Test类
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Student []s = new Student[5];
s[0] = new Student("张三", 18);
s[1] = new Student("李四", 19);
s[2] = new Student("张三", 50);
s[3] = new Student("李白", 5);
s[4] = new Student("王五", 10);
print(s);
// Arrays.sort(s,(o1, o2)-> o1.getAge() - o2.getAge());
// Arrays.sort(s, (o1, o2)->Student.compare(o1, o2));
//静态方法引用
Arrays.sort(s,Student::compare);
System.out.println("-------排序后:-------");
print(s);
}
//打印姓名和年龄
public static void print(Student []s){
for (int i = 0; i < s.length; i++){
System.out.println(s[i]);
}
}
}2、实例方法引用
语法
对象名::实例方法
使用场景
如果某个Lambda表达式里只是通过对象名称调用一个实例方法,并且“—>”前后参数的形式一致,就可以使用实例方法引用。
代码4:演示了实例引用使用场景
Student类
public class Student {
private String name;
private int age;
//构造器
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//实例方法方法引用
public int compare(Student o1, Student o2){
return o1.getAge() - o2.getAge();
}
}Test类
import java.util.Arrays;
public class Testt {
public static void main(String[] args) {
Student []s = new Student[5];
s[0] = new Student("张三", 18);
s[1] = new Student("李四", 19);
s[2] = new Student("张三", 50);
s[3] = new Student("李白", 5);
s[4] = new Student("王五", 10);
System.out.println("-------排序前:-------");
print(s);
Student t = new Student();
//实例方法引用:对象名::实例方法名
//前提:->前后参数形式一致,才能使用实例方法引用
Arrays.sort(s, t::compare);
System.out.println("-------排序后:-------");
print(s);
}
//打印姓名和年龄
public static void print(Student []s){
for (int i = 0; i < s.length; i++){
System.out.println(s[i]);
}
}
}
/*
输出结果:
-------排序前:-------
Student{name='张三', age=18}
Student{name='李四', age=19}
Student{name='张三', age=50}
Student{name='李白', age=5}
Student{name='王五', age=10}
-------排序后:-------
Student{name='李白', age=5}
Student{name='王五', age=10}
Student{name='张三', age=18}
Student{name='李四', age=19}
Student{name='张三', age=50}
*/3、特定类型方法的引用
语法
特定类型的名称::方法
使用场景
如果某个Lambda表达式里只是调用了一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用。
代码5:演示特定方法引用的使用场景。
Test类
import java.util.Arrays;
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
//给英语名称排序
String[] name = {"Tom", "Jerry", "Bobi", "曹操", "Mike","angela","Dlei","Jack","Andy","cao"};
System.out.println("排序前:" + Arrays.toString(name));
//把这个数组进行排序:
// Arrays.sort(name);
// System.out.println(Arrays.toString(name));
//要求,忽略大小写进行排序(Java官方默认是按照ASCII码进行排序的)所以我们的要求官方默认搞不懂,
// 需要我们自定义排序规则
// Arrays.sort(name, new Comparator<String>() {
// @Override
// public int compare(String o1, String o2) {
// return o1.compareToIgnoreCase(o2); //java已经为我们提供了字符串按照首字母忽略大小写比较方法:compareToIgnoreCase
// }
// });
//Lambda简化
// Arrays.sort(name, (o1, o2)->o1.compareToIgnoreCase(o2));
//特定类型方法引用:类型名::方法名
Arrays.sort(name, String::compareToIgnoreCase);
System.out.println("排序后:" + Arrays.toString(name));
Arrays.sort(name, String::compareToIgnoreCase);
}
}
/*
输出结果:
排序前:[Tom, Jerry, Bobi, 曹操, Mike, angela, Dlei, Jack, Andy, cao]
排序后:[Andy, angela, Bobi, cao, Dlei, Jack, Jerry, Mike, Tom, 曹操]
*/4、构造器引用
构造器引用(Constructor Reference) 是一种特殊的语法,用于引用一个类的构造器,并将其作为函数式接口的实例。它允许你将“创建对象”这个行为当作一个函数来传递,是 Lambda 表达式的简洁替代。
语法:
类名::new
使用场景
如果某个Lambda表达式里只是在创建对象,并且“—>”前后参数情况一致,就可以使用构造器引用。
代码6:理解构造器引用
Test类:
public class Test {
public static void main(String[] args) {
// CarFactory cf = new CarFactory() {
// @Override
// public Car getCar(String name) {
// return new Car(name);
// }
// };
//创建对象
// Car c = cf.getCar("法拉利");
//简化
// CarFactory cf = name-> new Car(name);
//用构造器引用简化
CarFactory cf = Car::new;
Car c = cf.getCar("法拉利");
System.out.println(c);
}
}
interface CarFactory{
Car getCar(String name); //接口中的抽象方法,返回值类型为Car
}
class Car{
private String name;
public Car(String name) {
this.name = name;
}
public Car(){}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
//重新toString
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
'}';
}
}
/*
输出结果:
Car{name='法拉利'}
*/到此这篇关于Java中的函数式编程Lambda、方法引用详解的文章就介绍到这了,更多相关java函数式编程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
IntelliJ IDEA 安装 Grep Console插件 自定义控制台输出多颜色格式功能
由于Intellij idea不支持显示ascii颜色,grep-console插件能很好的解决这个问题,下面就以开发JavaEE项目中,结合Log4j配置多颜色日志输出功能,感兴趣的朋友一起看看吧2020-05-05
springboot中用fastjson处理返回值为null的属性值
在本篇文章里小编给大家整理的是一篇关于springboot中用fastjson处理返回值问题详解内容,需要的朋友们参考下。2020-03-03


最新评论