Java中的函數式編程Lambda、方法引用詳解
引入
函數式編程中“函數”類似于數學中的函數(強調做什么),只要輸入的數據一致返回的結果也是一致的

函數式編程解決了什么問題?什么是函數式編程?
使用Lambda函數替代嗎某些匿名內部類對象,從而讓程序代碼更簡潔,可讀性更好。
一:Lambda
1、認識Lambda表達式
- JDK8開始新增的一種語法形式,它表示函數。
- 可以用于替代匿名內部類對象,從而讓程序更簡潔,可讀性更好。
- 注意:Lambda表達式只能替代函數式接口的匿名內部類?。。。?。
什么是函數式接口
- 有且僅有一個抽象方法的接口。
思考:為什么只能替代函數式接口的匿名內部類,分析:函數式接口只能有一個抽象方法,在簡化的時候,會找到這個抽象方法并為這個方法重寫。如果有多個抽象方法,簡化后:編譯器不知道要為那個抽象方法重寫。
Lambda表達式的書寫格式
(參數列表) -> { 表達式或語句塊 }(參數列表):定義 Lambda 表達式接受的參數。參數的類型通??梢杂删幾g器推斷,因此可以省略。->:稱為 Lambda 操作符 或 箭頭操作符。它將參數列表與 Lambda 主體分隔開。{ 表達式或語句塊 }:Lambda 表達式的主體,包含要執(zhí)行的代碼。- 如果表達式或語句塊:只有一句{ }可以省略,否則不可省略。
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實戰(zhàn)實例、省略規(guī)則
1.使用Lambda簡化comparator接口的匿名內部類

2.Lambda表達式的省略規(guī)則
作用:用于進一步簡化Lambda表達式寫法。
具體規(guī)則:
- 參數類型全部可以省略不寫。
- 如果只有一個參數,參數類型省略的同時“()”也可以省略,但是對個參數不能省略“()”。
- 如果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、靜態(tài)方法引用
靜態(tài)方法引用(Static Method Reference) 是一種特殊的語法,用于直接引用一個類的靜態(tài)方法,并將其作為函數式接口的實例。它是 Lambda 表達式的更簡潔替代形式。
語法:
類名::靜態(tài)方法名
類名: 定義了靜態(tài)方法的類的名稱。::方法引用操作符。靜態(tài)方法名: 要引用的靜態(tài)方法的名稱,不帶括號()和參數。
使用場景
如果某個Lambda表達式里只是調用一個靜態(tài)方法,并且“—>”前后參數的形式一致,(就像是下面的例子,->兩邊都是o1、o2)就可以使用靜態(tài)方法引用。
代碼3:下面代碼演示了靜態(tài)方法引用的使用場景
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 +
'}';
}
//靜態(tài) 方法引用
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));
//靜態(tài)方法引用
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碼進行排序的)所以我們的要求官方默認搞不懂,
// 需要我們自定義排序規(guī)則
// 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) 是一種特殊的語法,用于引用一個類的構造器,并將其作為函數式接口的實例。它允許你將“創(chuàng)建對象”這個行為當作一個函數來傳遞,是 Lambda 表達式的簡潔替代。
語法:
類名::new
使用場景
如果某個Lambda表達式里只是在創(chuàng)建對象,并且“—>”前后參數情況一致,就可以使用構造器引用。
代碼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);
// }
// };
//創(chuàng)建對象
// 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函數式編程內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
IntelliJ IDEA 安裝 Grep Console插件 自定義控制臺輸出多顏色格式功能
由于Intellij idea不支持顯示ascii顏色,grep-console插件能很好的解決這個問題,下面就以開發(fā)JavaEE項目中,結合Log4j配置多顏色日志輸出功能,感興趣的朋友一起看看吧2020-05-05
springboot中用fastjson處理返回值為null的屬性值
在本篇文章里小編給大家整理的是一篇關于springboot中用fastjson處理返回值問題詳解內容,需要的朋友們參考下。2020-03-03

