Java使用Streams時(shí)的7個(gè)常見錯(cuò)誤與解決方案
在使用 Java Streams 時(shí),以下是一些常見的錯(cuò)誤:
1.不使用終止操作
錯(cuò)誤:忘記調(diào)用終止操作(如collect()
、forEach()
或reduce()
),這會(huì)導(dǎo)致流沒有執(zhí)行。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 創(chuàng)建流但沒有調(diào)用終止操作 names.stream() .filter(name -> name.startsWith("A")); // 這里沒有調(diào)用終止操作 // 由于流沒有執(zhí)行,什么都不會(huì)打印 System.out.println("Stream operations have not been executed."); }
解決方案:始終以終止操作結(jié)束,以觸發(fā)流的處理。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 創(chuàng)建流并調(diào)用終止操作 names.stream() .filter(name -> name.startsWith("A")) // 中間操作 .forEach(System.out::println); // 終止操作 // 這將打印 "Alice",因?yàn)榱鞅粓?zhí)行了 }
2.修改源數(shù)據(jù)
錯(cuò)誤:在處理流時(shí)修改源數(shù)據(jù)結(jié)構(gòu)(如List
)可能導(dǎo)致未知的結(jié)果。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 嘗試在流處理時(shí)修改源列表 names.stream() .filter(name -> { if (name.startsWith("B")) { names.remove(name); // 修改源列表 } return true; }) .forEach(System.out::println); // 由于并發(fā)修改,輸出可能不符合預(yù)期 System.out.println("Remaining names: " + names); }
解決方案:不要在流操作期間修改源數(shù)據(jù),而是使用流創(chuàng)建新的集合。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 基于過濾結(jié)果創(chuàng)建一個(gè)新列表 List<String> filteredNames = names.stream() .filter(name -> name.startsWith("B")) // 過濾出以 'B' 開頭的名字 .collect(Collectors.toList()); // 顯示過濾后的列表 System.out.println("Filtered names: " + filteredNames); System.out.println("Original names remain unchanged: " + names); }
3.忽略并行流的開銷
錯(cuò)誤:認(rèn)為并行流總是能提高性能,而不考慮上下文,例如小數(shù)據(jù)集或輕量級(jí)操作。
public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 小數(shù)據(jù)集 // 在小數(shù)據(jù)集上使用并行流 numbers.parallelStream() .map(n -> { // 模擬輕量級(jí)操作 System.out.println(Thread.currentThread().getName() + " processing: " + n); return n * n; }) .forEach(System.out::println); // 輸出可能顯示為簡單任務(wù)創(chuàng)建了不必要的線程 }
解決方案:謹(jǐn)慎使用并行流,尤其是對(duì)于大數(shù)據(jù)集的 CPU 密集型任務(wù)。
public static void main(String[] args) { List<Integer> numbers = IntStream.rangeClosed(1, 1_000_000) // 大數(shù)據(jù)集 .boxed() .collect(Collectors.toList()); // 在大數(shù)據(jù)集上使用并行流進(jìn)行 CPU 密集型操作 List<Integer> squareNumbers = numbers.parallelStream() .map(n -> { // 模擬 CPU 密集型操作 return n * n; }) .collect(Collectors.toList()); // 打印前 10 個(gè)結(jié)果 System.out.println("First 10 squared numbers: " + squareNumbers.subList(0, 10)); }
4.過度使用中間操作
錯(cuò)誤:鏈?zhǔn)秸{(diào)用過多的中間操作(如filter()
和map()
)可能會(huì)引入性能開銷。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve"); // 過度使用中間操作 List<String> result = names.stream() .filter(name -> name.startsWith("A")) // 第一個(gè)中間操作 .filter(name -> name.length() > 3) // 第二個(gè)中間操作 .map(String::toUpperCase) // 第三個(gè)中間操作 .map(name -> name + " is a name") // 第四個(gè)中間操作 .toList(); // 終端操作 // 輸出結(jié)果 System.out.println(result); }
解決方案:盡量減少流管道中的中間操作,并在可能的情況下使用流融合。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve"); // 優(yōu)化流管道 List<String> result = names.stream() .filter(name -> name.startsWith("A") && name.length() > 3) // 將過濾器合并為一個(gè) .map(name -> name.toUpperCase() + " is a name") // 合并 map 操作 .toList(); // 終端操作 // 輸出結(jié)果 System.out.println(result); }
5.不處理 Optional 值
錯(cuò)誤:在使用findFirst()
或reduce()
等操作時(shí),沒有正確處理Optional
結(jié)果。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // 嘗試查找以 "Z" 開頭的名字(不存在) String firstNameStartingWithZ = names.stream() .filter(name -> name.startsWith("Z")) .findFirst() // 返回一個(gè) Optional .get(); // 如果 Optional 為空,這將拋出 NoSuchElementException // 輸出結(jié)果 System.out.println(firstNameStartingWithZ); }
解決方案:在訪問Optional
的值之前,始終檢查它是否存在,以避免NoSuchElementException
。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); // 正確處理 Optional Optional<String> firstNameStartingWithZ = names.stream() .filter(name -> name.startsWith("Z")) .findFirst(); // 返回一個(gè) Optional // 檢查 Optional 是否存在 if (firstNameStartingWithZ.isPresent()) { System.out.println(firstNameStartingWithZ.get()); } else { System.out.println("No name starts with 'Z'"); } }
6.忽略線程安全
錯(cuò)誤:在并行流中使用共享的可變狀態(tài)可能導(dǎo)致競(jìng)態(tài)條件和不一致的結(jié)果。
public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> results = new ArrayList<>(); // 共享的可變狀態(tài) // 在并行流中使用共享的可變狀態(tài) numbers.parallelStream().forEach(number -> { results.add(number * 2); // 這可能導(dǎo)致競(jìng)態(tài)條件 }); // 輸出結(jié)果 System.out.println("Results: " + results); }
解決方案:避免共享可變狀態(tài);使用線程安全的集合或局部變量。
public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> results = new CopyOnWriteArrayList<>(); // 線程安全的集合 // 在并行流中使用線程安全的集合 numbers.parallelStream().forEach(number -> { results.add(number * 2); // 避免競(jìng)態(tài)條件 }); // 輸出結(jié)果 System.out.println("Results: " + results); }
7.混淆中間操作和終止操作
錯(cuò)誤:不清楚中間操作(返回新流)和終止操作(產(chǎn)生結(jié)果)之間的區(qū)別。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 錯(cuò)誤:嘗試將中間操作用作終止操作 // 這將無法編譯,因?yàn)?'filter' 返回一個(gè) Stream,而不是一個(gè) List names.stream().filter(name -> name.startsWith("A")).forEach(System.out::println); // 這里正確使用了終止操作 }
解決方案:熟悉每種操作類型的特性,以避免代碼中的邏輯錯(cuò)誤。
public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); // 正確使用中間操作和終止操作 List<String> filteredNames = names.stream() .filter(name -> name.startsWith("A")) // 中間操作 .collect(Collectors.toList()); // 終止操作 // 輸出過濾后的名字 System.out.println("Filtered Names: " + filteredNames); }
通過掌握這些技巧并實(shí)施這些解決方案,你可以更好地使用 Java Streams,并編寫更簡潔、更高效的代碼。
到此這篇關(guān)于Java使用Streams時(shí)的7個(gè)常見錯(cuò)誤與解決方案的文章就介紹到這了,更多相關(guān)Java Streams常見錯(cuò)誤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SSH框架網(wǎng)上商城項(xiàng)目第24戰(zhàn)之Struts2中處理多個(gè)Model請(qǐng)求的方法
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第24戰(zhàn)之Struts2中處理多個(gè)Model請(qǐng)求的方法,感興趣的小伙伴們可以參考一下2016-06-06Springboot整合阿里巴巴SMS的實(shí)現(xiàn)示例
本文主要介紹了Springboot整合阿里巴巴SMS的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12學(xué)習(xí)JVM之java內(nèi)存區(qū)域與異常
關(guān)于JVM內(nèi)存區(qū)域的知識(shí)對(duì)于初學(xué)者來說其實(shí)是很重要的,了解Java內(nèi)存分配的原理,這對(duì)于以后JAVA的學(xué)習(xí)會(huì)有更深刻的理解。下面來看看詳細(xì)介紹。2016-07-07Java實(shí)戰(zhàn)之實(shí)現(xiàn)OA辦公管理系統(tǒng)
這篇文章主要介紹了如何通過Java實(shí)現(xiàn)OA辦公管理系統(tǒng),文章采用到了JSP、JQuery、Ajax等技術(shù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-02-02SSH框架網(wǎng)上商城項(xiàng)目第25戰(zhàn)之使用java email給用戶發(fā)送郵件
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第25戰(zhàn)之使用java email給用戶發(fā)送郵件,感興趣的小伙伴們可以參考一下2016-06-06Java中struts2和spring MVC的區(qū)別_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java中struts2和spring MVC的區(qū)別,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-09-09如何自定義hibernate validation注解示例代碼
Hibernate Validator 是 Bean Validation 的參考實(shí)現(xiàn) . Hibernate Validator 提供了 JSR 303 規(guī)范中所有內(nèi)置 constraint 的實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于如何自定義hibernate validation注解的相關(guān)資料,需要的朋友可以參考下2018-04-04Java?事務(wù)注解@Transactional回滾(try?catch、嵌套)問題
這篇文章主要介紹了Java?@Transactional回滾(try?catch、嵌套)問題,Spring?事務(wù)注解?@Transactional?本來可以保證原子性,如果事務(wù)內(nèi)有報(bào)錯(cuò)的話,整個(gè)事務(wù)可以保證回滾,但是加上try?catch或者事務(wù)嵌套,可能會(huì)導(dǎo)致事務(wù)回滾失敗2022-08-08