Lambda運算式
1. 函式式編程思想
- 面向物件強調:萬物節皆物件,我們做任何事情都需要通過物件
- 函式式編程思想強調:盡量忽略面向物件的復雜語法,強調做什么,而不是通過什么去做
所以,我們先來完成一個簡單的案例,感受下Lambda運算式是如何“直擊要點”的~
2. 案例引入
需求:在多執行緒場景下,在控制臺輸出:多執行緒程式啟動啦
思路1:創建自定義多執行緒類實作Runnble介面,創建物件啟動
思路2:優化使用匿名內部類的方式來完成
思路3:使用Lambda運算式來完成
package cn.cxy.lambda;
/*本類用于lambda運算式入門
* 需求:在多執行緒場景下,在控制臺輸出:多執行緒程式啟動啦*/
public class LambdaDemo {
public static void main(String[] args) {
//2.創建目標業務類物件
MyRunnable target = new MyRunnable();
//3.將目標業務類物件作為Thread類的構造引數傳入
Thread t = new Thread(target);
//4.啟動執行緒
t.start();
/*方案二:改進:使用匿名內部類的方式:*/
//5.使用匿名內部類的方式改進
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("多執行緒程式2啟動啦");
}
}).start();
/*方案三:繼續改進:使用lambda運算式的方式:*/
new Thread( () -> {
System.out.println("多執行緒程式3啟動啦");
}).start();
}
}
/*實作方案1:以介面實作類的方式實作*/
//1.定義多執行緒類實作Runnable介面,重寫run()
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("多執行緒程式啟動啦");
}
}
3. Lambda運算式的標準格式
我們先來分析下以匿名內部類方式撰寫代碼的格式 :
- 方法引數串列處的引數為空,說明本方法執行時不需要傳參
- 方法的回傳值型別為void,說明這個方法的執行并沒有回傳結果
- 方法體中的內容才是我們具體要做的業務
我們再來分析下以Lambda運算式方法撰寫代碼的格式 :
- ()里面沒有內容,我們可以把它看作是方法執行時不需要傳引數,引數為空
- -> : 用箭頭表示我們即將要做的事,也就是具體要做的業務
- { } : 我們可以把它看作是一個代碼塊代表了之前我們在方法體中需要寫的業務內容

總結:Lambda運算式的標準格式為:(方法的形式引數)-> { 方法體 }
1)如果有多個引數,引數之間用逗號隔開,如果沒有引數,小括號里面為空
2)-> 是一個固定的標準寫法,使用的符號都是英文的,代表我們指向要操作的動作
3){ } 里是我們具體要完成的業務,也就是我們方法的方法體
注意Lambda運算式的前提:介面+介面中有且僅有一個抽象方法
4.1 案例練習1:抽象方法無引數無回傳值時:
創建介面:Animal
package cn.cxy.lambda;
//1.定義介面
public interface Animal {
//2.定義介面中沒有引數也沒有回傳值的抽象方法
void eat();
}
創建介面的實作類:AnimalImpl
package cn.cxy.lambda;
//3.創建介面的實作類并實作方法
public class AnimalImpl implements Animal{
@Override
public void eat() {
System.out.println("小動物吃啥都行~");
}
}
創建測驗類:TestAnimal
package cn.cxy.lambda;
//4.創建測驗類
public class TestAnimal {
public static void main(String[] args) {
/*方案1:創建介面實作類物件呼叫*/
//6.1創建介面的實作類物件【多型物件】
Animal a = new AnimalImpl();
//6.2呼叫本類的getAnimal(),并把剛剛創建的多型物件傳入
getAnimal(a);//小動物吃啥都行~
/*方案2:使用匿名內部類的方式來呼叫*/
//7.直接呼叫getAnimal(),引數處以創建匿名內部類的方式來完成
getAnimal(new Animal() {
@Override
public void eat() {
System.out.println("小動物現在都想吃小蘋果~");
}
});
/*方案3:使用Lambda運算式來完成
* eat()沒有引數,小括號為空,指向eat()里實際要執行的一句列印陳述句 */
getAnimal( () -> {
System.out.println("Lambda運算式的方式,小動物們都驚呆了~");
});
}
//5.創建測驗類中的方法getAnimal()
public static void getAnimal(Animal a){
a.eat();
}
}
4.2 案例練習2:抽象方法有引數無回傳值時:
創建介面:Fruit
package cn.cxy.lambda;
//1.創建介面
public interface Fruit {
//2.創建介面中帶引數的抽象方法
void getKind(String s);
}
創建介面測驗類FruitImpl:
package cn.cxy.lambda;
//3.創建介面的實作類并實作抽象方法
public class FruitImpl implements Fruit{
@Override
public void getKind(String s) {
System.out.println("引數s是:"+s);
System.out.println("我是一個大桃子~");
}
}
創建測驗類TestFruit:
package cn.cxy.lambda;
//4.創建測驗類進行測驗
public class TestFruit {
public static void main(String[] args) {
/*方案1:創建介面實作類物件呼叫*/
//6.1創建介面的實作類物件【多型物件】
Fruit f = new FruitImpl();
//6.2呼叫本類的getFruit(),并把剛剛創建的多型物件傳入
getFruit(f);
/*方案2:使用匿名內部類的方式來呼叫*/
//7.直接呼叫getFruit(),引數處以創建匿名內部類的方式來完成
getFruit(new Fruit() {
@Override
public void getKind(String s) {
System.out.println("引數s是:"+s);
System.out.println("我是一個大橙子~");
}
});
/*方案3:使用Lambda運算式來完成
* eat()沒有引數,小括號為空,指向eat()里實際要執行的一句列印陳述句 */
getFruit( (String s) -> {
System.out.println("引數s是:"+s);
System.out.println("我是一顆大草莓");
});
}
//5.創建測驗類的方法,需要傳入介面物件,并且呼叫介面的功能
public static void getFruit(Fruit f){
f.getKind("猜猜我是什么水果?");
}
}
4.3 案例練習3:抽象方法有引數有回傳值時:
創建介面:Student
package cn.cxy.lambda;
//1.創建介面
public interface Student {
//2.創建介面中帶引數并且有回傳值的抽象方法
int scoreCount(int a,int b,int c);
}
創建介面的實作類:
package cn.cxy.lambda;
//3.創建介面的實作類并實作抽象方法
public class StudentImpl implements Student{
@Override
public int scoreCount(int a, int b, int c) {
return a+b+c;
}
}
創建測驗類TestStudent:
package cn.cxy.lambda;
//4.創建測驗類進行測驗
public class TestStudent {
public static void main(String[] args) {
/*方案1:創建介面實作類物件呼叫*/
//6.1創建介面的實作類物件【多型物件】
Student s = new StudentImpl();
//6.2呼叫本類的getFruit(),并把剛剛創建的多型物件傳入
getScore(s);
/*方案2:匿名內部類的方式來呼叫也不簡單,故此直接使用Lambda運算式來完成:
* 呼叫本方法時,將下方的引數60 70 80 作為引數傳入*/
//7.直接使用Lambda運算式進行優化
getScore((int x,int y,int z) ->{
return x+y+z;//scoreCount()正常回傳方法的回傳值,交給下方的score變數來保存
});
}
//5.創建測驗類的方法,需要傳入介面物件,并且呼叫介面的功能
public static void getScore(Student s) {
int score = s.scoreCount(60, 70, 80);
System.out.println("總分為:"+score);
}
}
5. Lambda運算式的省略模式
- 在TestStudent測驗類中,我們來學習Lambda運算式的簡寫形式1:
/*Lambda運算式的省略模式1:
* 引數的型別可以省略,但注意,如果有多個引數,不能只省略一個*/
//getScore((int x,int y,int z) ->{//之前的寫法
//getScore((x,int y, int z) ->{//會報錯
getScore((x,y,z) ->{//現在省略了所有引數的型別
return x+y+z;//scoreCount()正常回傳方法的回傳值,交給下方的score變數來保存
});
結論:引數的型別可以省略,但注意,如果有多個引數,不能只省略一個
- 在TestFruit測驗類中,我們來學習Lambda運算式的簡寫形式2:
/*Lambda運算式的省略模式2:
* 如果方法的引數有且只有一個,引數的小括號可以省略*/
//getFruit( (String s) -> {//之前的寫法,現在省略的引數的型別與小括號
getFruit( s -> {
System.out.println("引數s是:"+s);
System.out.println("我是一顆大草莓");
});
結論:如果方法的引數有且只有一個,引數的小括號可以省略
- 在TestAnimal測驗類中,我們來學習Lambda運算式的簡寫形式3:
/*Lambda運算式的省略模式3:
* 如果大括號里的方法體只有一句,可以省略大括號和分號*/
getAnimal( () ->
System.out.println("Lambda運算式的方式,小動物們都驚呆了~")
);
結論;如果大括號里的方法體只有一句,可以省略大括號和分號
- 在TestStudent測驗類中,我們來學習Lambda運算式的簡寫形式4:
/*Lambda運算式的省略模式4:
* 如果方法體只有一句,大括號與分號可以省略
* 除此之外,如果方法用關鍵字return回傳回傳值,return也需要一起省略掉*/
getScore((x,y,z) -> x+y+z );
結論;如果方法體里有return用來回傳回傳值,return也需要一起省略掉
6. Lambda運算式的注意事項:
- 必須是有一個介面,并且介面中只有一個抽象方法時使用
- 使用運算式時必須要有背景關系環境推匯出Lambda實際代表的介面
package cn.cxy.lambda;
public class TestLambda {
public static void main(String[] args) {
/*方式1:匿名內部類*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("執行緒啟動啦");
}
}).start();
/*方式2:Lambda運算式寫法1:根據區域變數r的型別推匯出Lambda代表的介面*/
Runnable r = () -> System.out.println("用參考型別變數推斷Lambda表示的是哪個介面");
new Thread(r).start();
/*方式3:Lambda運算式寫法2:根據呼叫Thread(Runnable)方法的引數型別推匯出Lambda代表的介面*/
new Thread(()-> System.out.println("Lambda方式執行緒啟動啦")).start();
}
}
- 匿名內部類與Lambda運算式的區別/使用場景:
1)不論被呼叫方法的引數是介面/抽象類/物體類,匿名內部類的形式均可以使用
但是Lambda運算式只能是被呼叫方法引數為介面的時候使用
2)不論介面里有幾個抽象方法,都可以使用匿名內部類的形式
但是Lambda運算式只支持介面中有且僅有一個抽象方法的情況
3)實作原理不同:匿名內部類生效后會多產生一個額外單獨的內部類位元組碼檔案
而Lambda運算式只有一個位元組碼檔案

創建介面:
package cn.cxy.lambda;
//1.創建介面與介面中的抽象方法
public interface Inter {
void eat();
}
創建抽象類:
package cn.cxy.lambda;
//2.創建抽象類與抽象類中的方法
public abstract class abstractClass {
abstract void sleep();
public void sleep2(){
System.out.println("一天要睡夠8小時哦~");
}
}
創建普通類:
```java
package cn.cxy.lambda;
//3.創建普通物體類與類中的方法
public class normalClass {
public void play(){
System.out.println("最愛玩的就是代碼啦~");
}
}
創建測驗類:
package cn.cxy.lambda;
public class TestAnonymousAndLambda {
public static void main(String[] args) {
useFunction1(new Inter() {
@Override
public void eat() {
System.out.println("吃火鍋~");
}
});
useFunction2(new abstractClass() {
@Override
void sleep() {
System.out.println("睡10個小時吧~");
}
});
useFunction3(new normalClass() {
@Override
public void play() {
System.out.println("代碼寫累了,完會游戲吧~");
}
});
useFunction1(()-> System.out.println("我是介面形式"));
//useFunction2(()-> System.out.println("我是抽象類的形式"));//會報錯,不支持抽象類
//useFunction3(()-> System.out.println("我是普通物體類的形式"));//會報錯,不支持普通類
}
public static void useFunction1(Inter i) {
i.eat();
}
public static void useFunction2(abstractClass a) {
a.sleep();
}
public static void useFunction3(normalClass n) {
n.play();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/302554.html
標籤:其他
