Java值得使用Lambda的8個(gè)場(chǎng)景合集
前言
可能對(duì)不少人來(lái)說(shuō),Lambda顯得陌生又復(fù)雜,覺(jué)得Lambda會(huì)導(dǎo)致代碼可讀性下降,詬病Lambda語(yǔ)法,甚至排斥。
其實(shí)所有的這些問(wèn)題,在嘗試并熟悉后,可能都不是問(wèn)題。
對(duì)Lambda持懷疑態(tài)度的人,也許可以采取漸進(jìn)式使用Lambda的策略。在一些簡(jiǎn)單和低風(fēng)險(xiǎn)的場(chǎng)景下先嘗試使用Lambda,逐漸增加Lambda表達(dá)式的使用頻率和范圍。
畢竟2023年了,JDK都出了那么多新版本,是時(shí)候試試Lambda了!
耐心看完,你一定有所收獲。
1. 對(duì)集合進(jìn)行遍歷和篩選
使用Lambda表達(dá)式結(jié)合Stream API可以在更少的代碼量下實(shí)現(xiàn)集合的遍歷和篩選,更加簡(jiǎn)潔和易讀。
原來(lái)的寫(xiě)法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); for (Integer num : numbers) { if (num % 2 == 0) { System.out.println(num); } }
優(yōu)化的Lambda寫(xiě)法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.stream() .filter(num -> num % 2 == 0) .forEach(System.out::println);
2. 對(duì)集合元素進(jìn)行排序
使用Lambda表達(dá)式可以將排序邏輯以更緊湊的形式傳遞給sort方法,使代碼更加簡(jiǎn)潔。
原來(lái)的寫(xiě)法:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); Collections.sort(names, new Comparator<String>() { public int compare(String name1, String name2) { return name1.compareTo(name2); } });
優(yōu)化的Lambda寫(xiě)法:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); names.sort((name1, name2) -> name1.compareTo(name2));
3. 集合的聚合操作
Lambda表達(dá)式結(jié)合Stream API可以更優(yōu)雅地實(shí)現(xiàn)對(duì)集合元素的聚合操作,例如求和、求平均值等。
原來(lái)的寫(xiě)法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = 0; for (Integer num : numbers) { sum += num; }
優(yōu)化的Lambda寫(xiě)法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); int sum = numbers.stream() .reduce(0, Integer::sum);
4. 條件過(guò)濾和默認(rèn)值設(shè)置
使用Lambda的Optional類可以更加優(yōu)雅地處理?xiàng)l件過(guò)濾和默認(rèn)值設(shè)置的邏輯。
原來(lái)的寫(xiě)法:
String name = "Alice"; if (name != null && name.length() > 0) { System.out.println("Hello, " + name); } else { System.out.println("Hello, Stranger"); }
Lambda寫(xiě)法:
String name = "Alice"; name = Optional.ofNullable(name) .filter(n -> n.length() > 0) .orElse("Stranger"); System.out.println("Hello, " + name);
5. 簡(jiǎn)化匿名內(nèi)部類
可以簡(jiǎn)化代碼,同時(shí)提高代碼可讀性。
舉個(gè)創(chuàng)建Thread
的例子,傳統(tǒng)方式使用匿名內(nèi)部類來(lái)實(shí)現(xiàn)線程,語(yǔ)法較為冗長(zhǎng),而Lambda表達(dá)式可以以更簡(jiǎn)潔的方式達(dá)到相同的效果。
原來(lái)的寫(xiě)法:
new Thread(new Runnable() { public void run() { System.out.println("Thread is running."); } }).start();
Lambda寫(xiě)法:
new Thread(() -> System.out.println("Thread is running.")).start(); new Thread(() -> { // 做點(diǎn)什么 }).start();
這種寫(xiě)法也常用于簡(jiǎn)化回調(diào)函數(shù),再舉個(gè)例子:
假設(shè)我們有一個(gè)簡(jiǎn)單的接口叫做Calculator,它定義了一個(gè)單一的方法calculate(int a, int b)來(lái)執(zhí)行數(shù)學(xué)運(yùn)算:
// @FunctionalInterface: 標(biāo)識(shí)接口是函數(shù)式接口,只包含一個(gè)抽象方法,從而能夠使用Lambda表達(dá)式來(lái)實(shí)現(xiàn)接口的實(shí)例化 @FunctionalInterface interface Calculator { int calculate(int a, int b); }
現(xiàn)在,讓我們創(chuàng)建一個(gè)名為CallbackExample的類。該類有一個(gè)名為operate的方法,它接受兩個(gè)整數(shù)和一個(gè)Calculator接口作為參數(shù)。該方法將使用提供的Calculator接口執(zhí)行計(jì)算并返回結(jié)果:
public class CallbackExample { public static int operate(int a, int b, Calculator calculator) { return calculator.calculate(a, b); } public static void main(String[] args) { int num1 = 10; int num2 = 5; // 使用Lambda作為回調(diào) int sum = operate(num1, num2, (x, y) -> x + y); int difference = operate(num1, num2, (x, y) -> x - y); int product = operate(num1, num2, (x, y) -> x * y); int division = operate(num1, num2, (x, y) -> x / y); System.out.println("Sum: " + sum); System.out.println("Difference: " + difference); System.out.println("Product: " + product); System.out.println("Division: " + division); } }
通過(guò)在方法調(diào)用中直接定義計(jì)算的行為,我們不再需要為每個(gè)運(yùn)算創(chuàng)建多個(gè)實(shí)現(xiàn)Calculator接口的類,使得代碼更加簡(jiǎn)潔和易讀
6. 集合元素的轉(zhuǎn)換
使用Lambda的map方法可以更優(yōu)雅地對(duì)集合元素進(jìn)行轉(zhuǎn)換,提高代碼的可讀性
原來(lái)的寫(xiě)法:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); List<String> uppercaseNames = new ArrayList<>(); for (String name : names) { uppercaseNames.add(name.toUpperCase()); }
Lambda寫(xiě)法:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); List<String> uppercaseNames = names.stream() .map(String::toUpperCase) .collect(Collectors.toList());
7. 對(duì)集合進(jìn)行分組和統(tǒng)計(jì)
以更緊湊的形式傳遞分組和統(tǒng)計(jì)的邏輯,避免了繁瑣的匿名內(nèi)部類的聲明和實(shí)現(xiàn)。
通過(guò)groupingBy、counting、summingInt等方法,使得代碼更加流暢、直觀且優(yōu)雅。
傳統(tǒng)寫(xiě)法:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Amy", "Diana"); // 對(duì)名字長(zhǎng)度進(jìn)行分組 Map<Integer, List<String>> namesByLength = new HashMap<>(); for (String name : names) { int length = name.length(); if (!namesByLength.containsKey(length)) { namesByLength.put(length, new ArrayList<>()); } namesByLength.get(length).add(name); } System.out.println("Names grouped by length: " + namesByLength); // 統(tǒng)計(jì)名字中包含字母'A'的個(gè)數(shù) List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Amy", "Diana"); int namesWithA = 0; for (String name : names) { if (name.contains("A")) { namesWithA++; } } System.out.println("Number of names containing 'A': " + namesWithA);
Lambda寫(xiě)法:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Amy", "Diana"); // 使用Lambda表達(dá)式對(duì)名字長(zhǎng)度進(jìn)行分組 Map<Integer, List<String>> namesByLength = names.stream() .collect(Collectors.groupingBy(String::length)); System.out.println("Names grouped by length: " + namesByLength); // 使用Lambda表達(dá)式統(tǒng)計(jì)名字中包含字母'A'的個(gè)數(shù) long namesWithA = names.stream() .filter(name -> name.contains("A")) .count(); System.out.println("Number of names containing 'A': " + namesWithA);
8. 對(duì)大數(shù)據(jù)量集合的并行處理
當(dāng)集合的數(shù)據(jù)量很大時(shí),通過(guò)Lambda結(jié)合Stream API可以方便地進(jìn)行并行處理,充分利用多核處理器的優(yōu)勢(shì),提高程序的執(zhí)行效率。
假設(shè)我們有一個(gè)包含一百萬(wàn)個(gè)整數(shù)的列表,我們想要計(jì)算這些整數(shù)的平均值:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadLocalRandom; public class ParallelStreamExample { public static void main(String[] args) { // 創(chuàng)建一個(gè)包含一百萬(wàn)個(gè)隨機(jī)整數(shù)的列表 List<Integer> numbers = new ArrayList<>(); for (int i = 0; i < 1000000; i++) { numbers.add(ThreadLocalRandom.current().nextInt(100)); } // 順序流的處理 long startTimeSeq = System.currentTimeMillis(); double averageSequential = numbers.stream() .mapToInt(Integer::intValue) .average() .getAsDouble(); long endTimeSeq = System.currentTimeMillis(); System.out.println("Sequential Average: " + averageSequential); System.out.println("Time taken (Sequential): " + (endTimeSeq - startTimeSeq) + "ms"); // 并行流的處理 long startTimePar = System.currentTimeMillis(); double averageParallel = numbers.parallelStream() .mapToInt(Integer::intValue) .average() .getAsDouble(); long endTimePar = System.currentTimeMillis(); System.out.println("Parallel Average: " + averageParallel); System.out.println("Time taken (Parallel): " + (endTimePar - startTimePar) + "ms"); } }
分別使用順序流和并行流來(lái)計(jì)算列表中整數(shù)的平均值:
- 順序流:通過(guò)stream()方法獲取流,使用mapToInt將Integer轉(zhuǎn)換為int,然后使用average()方法計(jì)算平均值
- 并行流:使用parallelStream()方法獲取并行流,其他步驟與順序流相同
查看輸出結(jié)果:
Sequential Average: 49.517461
Time taken (Sequential): 10ms
Parallel Average: 49.517461
Time taken (Parallel): 3ms
可以看出,順序流和并行流得到了相同的平均值,但并行流的處理時(shí)間明顯少于順序流。因?yàn)椴⑿辛髂軌驅(qū)⑷蝿?wù)拆分成多個(gè)小任務(wù),并在多個(gè)處理器核心上同時(shí)執(zhí)行這些任務(wù)。
當(dāng)然并行流也有缺點(diǎn):
- 對(duì)于較小的數(shù)據(jù)集,可能并行流更慢
- 數(shù)據(jù)處理本身的開(kāi)銷較大,比如復(fù)雜計(jì)算、大量IO操作、網(wǎng)絡(luò)通信等,可能并行流更慢
- 可能引發(fā)線程安全問(wèn)題
收尾
Lambda的使用場(chǎng)景遠(yuǎn)不止這些,在多線程、文件操作等場(chǎng)景中也都能靈活運(yùn)用,一旦熟悉后可以讓代碼更簡(jiǎn)潔,實(shí)現(xiàn)精準(zhǔn)而優(yōu)雅的編程。
寫(xiě)代碼時(shí),改變偏見(jiàn)需要我們勇于嘗試和付諸行動(dòng)。有時(shí)候,我們可能會(huì)對(duì)某種編程語(yǔ)言、框架或設(shè)計(jì)模式持有偏見(jiàn),認(rèn)為它們不適合或不好用。但是,只有嘗試去了解和實(shí)踐,我們才能真正知道它們的優(yōu)點(diǎn)和缺點(diǎn)。
當(dāng)我們?cè)敢獯蚱婆f有的觀念,敢于嘗試新的技術(shù)和方法時(shí),我們就有機(jī)會(huì)發(fā)現(xiàn)新的可能性和解決問(wèn)題的新途徑。不要害怕失敗或犯錯(cuò),因?yàn)槊恳淮螄L試都是我們成長(zhǎng)和進(jìn)步的機(jī)會(huì)。
只要我們保持開(kāi)放的心態(tài),不斷學(xué)習(xí)和嘗試,我們就能夠超越偏見(jiàn),創(chuàng)造出更優(yōu)秀的代碼和解決方案。
所以,讓我們?cè)诰幊痰穆飞?,積極地去挑戰(zhàn)和改變偏見(jiàn)。用行動(dòng)去證明,只有不斷地嘗試,我們才能取得更大的進(jìn)步和成功。讓我們敢于邁出第一步,勇往直前,一同創(chuàng)造出更美好的編程世界!
以上就是Java值得使用Lambda的8個(gè)場(chǎng)景合集的詳細(xì)內(nèi)容,更多關(guān)于Java Lambda的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
手把手帶你入門(mén) Spring Security的具體流程
這篇文章主要介紹了手把手帶你入門(mén) Spring Security,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08SpringBoot Session接口驗(yàn)證實(shí)現(xiàn)流程詳解
這篇文章主要介紹了SpringBoot+Session實(shí)現(xiàn)接口驗(yàn)證(過(guò)濾器+攔截器)文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09java書(shū)店系統(tǒng)畢業(yè)設(shè)計(jì) 用戶模塊(2)
這篇文章主要介紹了java書(shū)店系統(tǒng)畢業(yè)設(shè)計(jì),第二步系統(tǒng)總體設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Java中的clone方法詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
clone顧名思義就是復(fù)制, 在Java語(yǔ)言中, clone方法被對(duì)象調(diào)用,所以會(huì)復(fù)制對(duì)象。下面通過(guò)本文給大家介紹java中的clone方法,感興趣的朋友一起看看吧2017-06-06macbook中springboot的jmeter壓測(cè)示例
這篇文章主要介紹了macbook中springboot的jmeter壓測(cè)示例詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11詳解如何將JAR包發(fā)布到Maven中央倉(cāng)庫(kù)
這篇文章主要介紹了詳解如何將JAR包發(fā)布到Maven中央倉(cāng)庫(kù),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-01-01