表達式的值為4,進階13 Lambda表達式

 2023-11-30 阅读 18 评论 0

摘要:Lambda表達式 函數式編程思想概述 在數學中,函數就是有輸入量、輸出量的一套計算方案,也就是“拿什么東西做什么事情”。相對而言,面向對象過分強調“必須通過對象的形式來做事情”,而函數式思想則盡量忽略面向對象的復雜語法——強調做什么ÿ

Lambda表達式

函數式編程思想概述

在數學中,函數就是有輸入量、輸出量的一套計算方案,也就是“拿什么東西做什么事情”。相對而言,面向對象過分強調“必須通過對象的形式來做事情”,而函數式思想則盡量忽略面向對象的復雜語法——強調做什么,而不是以什么形式做。
面向對象的思想:
? 做一件事情,找一個能解決這個事情的對象,調用對象的方法,完成事情.
函數式編程思想:
? 只要能獲取到結果,誰去做的,怎么做的都不重要,重視的是結果,不重視過程

冗余的Runnable代碼

    創建Runnable接口的實現類,重寫run方法,設置線程任務public class RunnableImpl implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 新線程創建了");}
}
public static void main(String[] args) {//創建Runnable接口的實現類對象RunnableImpl run = new RunnableImpl();//創建Thread類對象,構造方法中傳遞Runnable接口的實現類Thread t = new Thread(run);//調用start方法開啟新線程,執行run方法t.start();//簡化代碼,使用匿名內部類,實現多線程程序Runnable r = new Runnable(){@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 新線程創建了");}};new Thread(r).start();//繼續簡化代碼,直接傳遞匿名內部類new Thread(new Runnable(){@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 新線程創建了");}}).start();}
}

表達式的值為4,代碼分析
對于Runnable的匿名內部類用法,可以分析出幾點內容:
Thread類需要Runnable接口作為參數,其中的抽象run方法是用來指定線程任務內容的核心;
為了指定run的方法體,不得不需要Runnable接口的實現類;
為了省去定義一個RunnableImpl實現類的麻煩,不得不使用匿名內部類;
必須覆蓋重寫抽象run方法,所以方法名稱、方法參數、方法返回值不得不再寫一遍,且不能寫錯;
而實際上,似乎只有方法體才是關鍵所在。

Lambda表達式的標準格式:

由三部分組成:a.一些參數b.一個箭頭c.一段代碼

格式:

(參數列表) -> {一些重寫方法的代碼};

以下表達式值為3的是,解釋說明格式:

():接口中抽象方法的參數列表,沒有參數,就空著;有參數就寫出參數,多個參數使用逗號分隔
->:傳遞的意思,把參數傳遞給方法體{}
{}:重寫接口的抽象方法的方法體

public static void main(String[] args) {//使用匿名內部類的方式,實現多線程new Thread(new Runnable(){@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+" 新線程創建了");}}).start();//使用Lambda表達式,實現多線程new Thread(()->{   //()空括號中為空,其實就是run方法中的參數為空System.out.println(Thread.currentThread().getName()+" 新線程創建了");}).start();//優化省略Lambdanew Thread(()->System.out.println(Thread.currentThread().getName()+" 新線程創建了")).start();
}

用Lambda標準格式(無參無返回)

題目
給定一個廚子Cook接口,內含唯一的抽象方法makeFood,且無參數、無返回值。如下:

java public interface Cook { void makeFood(); }

在下面的代碼中,請使用Lambda的標準格式調用invokeCook方法,打印輸出“吃飯啦!”字樣:

private static void invokeCook(Cook cook) {cook.makeFood();
}

代碼實現:
定一個廚子Cook接口,內含唯一的抽象方法makeFood

public interface Cook {//定義無參數無返回值的方法makeFoodpublic abstract void makeFood();
}
需求:給定一個廚子Cook接口,內含唯一的抽象方法makeFood,且無參數、無返回值。使用Lambda的標準格式調用invokeCook方法,打印輸出“吃飯啦!”字樣public class Demo01Cook {public static void main(String[] args) {//調用invokeCook方法,參數是Cook接口,傳遞Cook接口的匿名內部類對象invokeCook(new Cook() {@Overridepublic void makeFood() {System.out.println("吃飯了");}});//現在使用Lambda表達式,簡化匿名內部類的書寫invokeCook(()->{//無參數,空括號System.out.println("吃飯了");});//優化省略LambdainvokeCook(()-> System.out.println("吃飯了"));}//定義一個方法,參數傳遞Cook接口,方法內部調用Cook接口中的方法makeFoodpublic static void invokeCook(Cook cook){cook.makeFood();}
}

Lambda的參數和返回值

需求: 使用數組存儲多個Person對象 對數組中的Person對象使用Arrays的sort方法通過年齡進行升序排序
下面舉例演示java.util.Comparator接口的使用場景代碼,其中的抽象方法定義為:

public abstract int compare(T o1, T o2);

當需要對一個對象數組進行排序時,Arrays.sort方法需要一個Comparator接口實例來指定排序的規則。
假設有一個Person類,含有String name和int age兩個成員變量:

 java public class Person { private String name; private int age;
// 省略構造器、toString方法與Getter Setter 
} 
 Lambda表達式有參數有返回值的練習需求:使用數組存儲多個Person對象對數組中的Person對象使用Arrays的sort方法通過年齡進行升序排序*/
public class Demo01Arrays {public static void main(String[] args) {//使用數組存儲多個Person對象Person[] arr = {new Person("張小敬",18),new Person("李必",20)};//對數組中的Person對象使用Arrays的sort方法通過年齡進行升序(前邊-后邊)排序Arrays.sort(arr, new Comparator<Person>() {@Overridepublic int compare(Person o1, Person o2) {return o1.getAge()-o2.getAge();}});//使用Lambda表達式,簡化匿名內部類Arrays.sort(arr,(Person o1, Person o2)->{return o1.getAge()-o2.getAge();});//優化省略LambdaArrays.sort(arr,(o1, o2)->o1.getAge()-o2.getAge());//遍歷數組for (Person p : arr) {System.out.println(p);}}
}

練習:使用Lambda標準格式(有參有返回) 自定義接口

給定一個計算器Calculator接口,內含抽象方法calc可以將兩個int數字相加得到和值

public interface Calculator {//定義一個計算兩個int整數和的方法并返回結果public abstract int calc(int a, int b);//有參數傳入,需要實現類重寫該方法
}
/*定義一個方法參數傳遞兩個int類型的整數參數傳遞Calculator接口方法內部調用Calculator中的方法 calc計算兩個整數的和*/
public static void invokeCalc(int a,int b,Calculator c){//參數有三個,其中一個是接口int sum = c.calc(a,b);System.out.println(sum);
}
public static void main(String[] args) {//調用invokeCalc方法,方法的參數是一個接口,可以使用匿名內部類invokeCalc(10, 20, new Calculator() {//new一個匿名內部類@Overridepublic int calc(int a, int b) {return a+b;}});//使用Lambda表達式簡化匿名內部類的書寫invokeCalc(120,130,(int a,int b)->{return a+b;});//優化省略LambdainvokeCalc(120,130,(a,b)-> a + b);
}

Lambda省略格式

可推導即可省略

    Lambda強調的是“做什么”而不是“怎么做”,所以凡是可以根據上下文推導得知的信息,都可以省略。例如上例還可以使用Lambda的省略寫法:
  java public static void main(String[] args) { invokeCalc(120, 130, (a, b) -> a + b); }

省略規則

    在Lambda標準格式的基礎上,使用省略寫法的規則為:小括號內參數的類型可以省略;如果小括號內有且僅有一個參數,則小括號可以省略;如果大括號內有且僅有一個語句,則無論是否有返回值,都可以省略大括號、return關鍵字及語句分號。上述代碼都寫出了省略格式。

小結:
可以省略的內容:
1.(參數列表):括號中參數列表的數據類型,可以省略不寫
2.(參數列表):括號中的參數如果只有一個,那么類型和()都可以省略
3.{一些代碼}:如果{}中的代碼只有一行,無論是否有返回值,都可以省略({},return,分號)
注意:要省略{},return,分號必須一起省略

public static void main(String[] args) {//JDK1.7版本之前,創建集合對象必須把前后的泛型都寫上ArrayList<String> list01 = new ArrayList<String>();//JDK1.7版本之后,=號后邊的泛型可以省略,后邊的泛型可以根據前邊的泛型推導出來ArrayList<String> list02 = new ArrayList<>();
}

Lambda的使用前提

Lambda的語法非常簡潔,完全沒有面向對象復雜的束縛。但是使用時有幾個問題需要特別注意:

  1. 使用Lambda必須具有接口,且要求接口中有且僅有一個抽象方法。 無論是JDK內置的Runnable、Comparator接口還是自定義的接口,只有當接口中的抽象方法存在且唯一時,才可以使用Lambda。
  2. 使用Lambda必須具有上下文推斷。 也就是方法的參數或局部變量類型必須為Lambda對應的接口類型,才能使用Lambda作為該接口的實例。
    備注:有且僅有一個抽象方法的接口,稱為“函數式接口”。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/186168.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息