Lambda表示式、函數語言程式設計思想概述
Lambda表示式
y = x + 1,在數學中,函式就是有輸入量,輸出量的一套計算方案;也就是“拿什麼東西,做什麼事情”。相對而言,面向物件過程過分強調“必須通過物件的形式來做事情”,而函數語言程式設計思想則儘量忽略面向物件的複雜語法---強調做什麼,而不是以什麼方式來做。
面向物件的思想:
做一件事情,找一個能解決這個事情的物件,呼叫物件的方法來完成事情。
函數語言程式設計的思想:
只要能獲得這個事情的結果,誰去做的,怎麼做的都不重要,重視的是結果,不重視過程。
冗餘的Runnable程式碼
當需要啟動一個執行緒去完成項任務時,通常會通過Runnable介面來定義任務內容,並且使用Thread類來啟動執行緒。
程式碼如下:
public static void main(String[] args) {
// 簡化程式碼
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "----->新執行緒被建立了!");
}
}).start();
}
函數語言程式設計思想
強調的是做什麼,而不是以什麼樣的方式來做,它忽略了面向物件的複雜語法,只要能夠獲取到結果,誰去做的,怎麼做的,
都不重要,重要的是結果,不重視過程。
冗餘的Runnable程式碼
傳統的寫法
public class Demo01Runnable { public static void main(String[] args) { //匿名內部類的方式 new Thread(new Runnable() { @Override public void run(){ System.out . println("開啟了一個新的執行緒任務"); } }).start();//啟動新執行緒 } }
程式碼分析:
對於Runnable的匿名內部類用法,可以分析出一下內容:
-
Thread類需要Runnable介面作為引數,其中抽象方法run用來指定執行緒任務內容的核心。
-
為了指定run方法的方法體,不得不需要Runnable介面的實現類
-
為了省去對義一個Runnablelmpl實現類的麻煩,不得不使用匿名內部類。
-
必須重寫抽象方法run方法,所以方法的名稱、方法的引數、方法的返回值不得不再寫一遍,且不能寫錯。
-
從這裡面可以,只有方法體才是執行緒任務的關鍵性內容
以程式設計思想的轉換
做什麼,而不是怎麼做
我們真正希望做的事情是:將run方法體的程式碼傳遞給Thread類知曉能夠載入到即可。
傳遞一段程式碼---這是我們真正的目的。
我們需要將程式關注的重點從怎麼做迴歸到做什麼,過程和形式並不重要。
體驗Lambda表示式的更優寫法
Java8的新特性,優化剛才的程式碼
public class Demo01Runnable {
public static void main(String[] args) {
//使用Lambda表示式的方式
new Thread(() -> {
System.out.println("開啟了一個新的執行緒任務");
}
).start();//啟動新執行緒
}
}
從上面的程式碼可以看出:沒有建立介面實現類物件的操作,也不再有抽象方法覆蓋重寫的操作,只寫了執行緒任務的內容。
從上面的程式碼能夠推匯出Lambda的語法:
() -> System.out.println("開啟了一個新的執行緒任務")
-
前面的一對小括號即run方法, 引數為無,裡面是空的,此時需要任何的條件
-
中間的一個箭頭代表將前面的引數傳遞給後面的程式碼
-
後面的輸出語句即業務邏輯程式碼(執行緒任務內容)
Lambda的標準格式
格式由三個部分組成:
-
一些引數
-
一個箭頭
-
一段程式碼
Lambda表示式的標準格式:
(引數型別1多數名稱1,引數型別2引數名稱.... ->{程式碼語句}
格式說明:
-
小括號的語法與傳統方法引數列表一致,無引數則置空,多個引數則用逗號隔開
-
->是新引入的語法格式,代表指向的動作
-
大括號的語法與傳統方法體要求基本一致。
練習:
定義一段廚子介面,該介面內內建了一個做飯的方法(抽象的方法),且無引數,無返回值,使用Lambda表示式,列印輸出“我今天吃的是紅燒茄子,吃的好開心”
public interface Chuzi {
//定義一個無參二u返回的方法
public abstract void zuofan() ;
}
public class TestChuzi {
public static void main(String[] args) {
invokeFood(() -> {
System.out.println( "我今天吃的是紅燒茄子,吃的好開心");
});
}
//定義一個方法, 引數的型別Cook介面,方法內部做- -個呼叫makeFood()
public static void invokeFood(Chuzi cook) {
cook.zuofan();
}
}
練習2:使用陣列儲存多個學生物件,對陣列中的學生物件使用Arrays的sort方法通過年齡進行升序排序。使用L ambda表示式來實現以上需求。
public class Student {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
public Student(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
}
//第二個類
public class Demo01Student{
public static void main(String[] args){
//使用陣列儲存多個學生物件
Student[] students = {new Student("小孫",20),new Student("小劉",18),new Student("小王",25),new Student("小趙",15)}
//1.傳統的寫法 匿名內部類方式
Arrays.sort(students,new Comparator<>(Student){
@Override
public int compare(Student s1,Student s2){
return s1.getAge()-s2.getAge();
}
});
//2.使用Lambda表示式 簡化匿名內部類
Arrats.sort(students,(Student s1,Student s2)->{
return s1.getAge()-s2.getAge();
});
//3.使用Lambda表示式的省略寫法
Arrays.sort(students,(s1,s2)->s1.getAge()-s2.getAge());
for(Student student : students){
System.out.println(student);
}
}
}
練習3:給定一個計算器介面, 內建了一個抽象方法計算的方法,可以將兩個double型別的數字相加得到和值。使用.ambda表達
式來實現以上需求。(有參有返回)
public interface Jisuanj{
double sum(double a,double b);
}
public class Jisuan{
public static void main(String[] args){
invokeSum(3.14,3.15,(double a,double b)->{
return a+b;
});
}
//定義一個方法
/*
* 引數傳遞兩個double值,再傳遞一個介面
* 方法內呼叫方法
*/
public static void invokeSum(double a,double b,Jisuanj ji){
double sum = ji.sum(a,b);
System.out.println("a+b="+sum);
}
}
Lambda省略格式
可推導即可省略
Lambda強詢的是“做什麼”,而不是“怎麼做”,所以凡是可以根據上下文推導得知的資訊,都可以省略。比如:
invokeSum(3.14, 3.15, (double d1,double d2) -> {
return d1 + d2;
});
//省略格式表達
invokeSum(3.14,3.15, (d1,d2) -> d1 + d2);
省略的規則:
在Lambda標準格式的表示式的基礎上,使用省略寫法的規則是:
-
小括號內參數的型別可以省略。
-
如果小括號內有且只有一個引數,則小括號也可以省略。
-
如果大括號內有且僅有一個語句,則無論是否有返回值,都可以省略大括號、retum關鍵字和語句的分號。
Lambda的使用前提
Lambda的語法非常的簡潔,使用非常的簡單,但是有以下注意事項:
-
使用L ambda必須具有介面,且要求介面中有且僅有一個抽象方法
無論JDK內建的Runnable、Comparator介面還是自定 義的介面,只有當介面中的抽象方法存在且唯一, 才可以使用Lambda -
使用Lambda必須具有上下文推斷。
也就是方法的引數或器區域性變數型別必須為Lambda對應的介面型別,才能使用Lambda作為該介面的例項。
備註:有且僅有一個抽象方法的介面,稱為函式的介面