Java中list.foreach不能使用字符串拼接的問題
list.foreach不能使用字符串拼接
如圖,不能使用String進行拼接
因為Lambda的本質實際上是匿名內部類,所以t必須是final類型(不過代碼中的final可以省略),是不可以重新賦值的。
可以使用
final StringBuilder str = new StringBuilder("已選擇:");
如圖二
foreach循環中不能使用字符串拼接
問題
@Test public void forEachTest(){ String str = "中國你好!"; List<String> list = Arrays.asList("a","b","c","d"); list.forEach(item->{ //編輯錯誤:Variable used in lambda expression should be final or effectively final str += item; }); //可以使用增強for // for (String item : list) { // str += item; // } System.out.println("結果:" + str); }
該編譯不通過的根本原因:Lambda表達式中的局部變量要使用final的問題。
因為String類型屬於引用數據類型,String字符串有不可變的特性,String在進行字符串拼接時,每次都會指向不同的地址值,因此str變量不能被看作是一個final類型,也就不符合Lambda表達式的使用要求。
解決
使用StringBuffer或StringBuilder:
@Test public void forEachTest(){ //String str = "中國你好!"; List<String> list = Arrays.asList("a","b","c","d"); StringBuffer stringbuffer = new StringBuffer("中國你好!"); list.forEach(item->{ stringbuffer .append(item); }); //可以使用增強for // for (String item : list) { // str += item; // } System.out.println("結果:" + sb); }
原理
StringBuffer是一個引用數據類型,在進行append()時,隻是修改瞭內容,並沒有改變地址值,這個stringbuffer變量就在編譯時看成瞭final類型的變量,因此可以使用。
Lambda表達式中的局部變量要使用final的問題
lambda表達式使用局部變量要用final
lambda表達式本身是一個匿名內部類的一種編寫形式,可以操作外部的變量
使用實例變量或靜態變量是沒有限制的(可認為是通過 final 類型的局部變量 this 來引用前兩者)
使用局部變量必須顯式的聲明為 final 或實際效果的的 final 類型,即該變量從未被改變過
@Test public void finalTest(){ String str = "中國你好!"; //在Lambda中使用該變量,該變量不能被修改過,java8會默認加上final //str = "c"; List<String> list = Arrays.asList("a","b","c","d"); List<String> collect = list.stream().filter(item -> { return item.equals(str); }).collect(Collectors.toList()); System.out.println("結果:" + collect); //不能改變str,否則Lambda表達式中編譯失敗 //str = "山東你好"; }
一個局部變量如果要在匿名類或是 Lambda 表達式中訪問,那麼這個局部變量必須是 final 的,即使沒有修飾為 final 類型,編譯器也會自動加上 final 修飾符。
在 Java 8 下,即使局部變量未聲明為 final 類型,一旦在 Lambda 表達式(匿名類) 中使用,就被強型加上瞭 final 屬性,所以後面就無法再次給 str 賦值瞭。
為什麼 Lambda 表達式(匿名類) 不能訪問非 final 的局部變量呢?
因為實例變量存在堆中,而局部變量是在棧上分配,Lambda 表達式(匿名類) 會在另一個線程中執行。如果在線程中要直接訪問一個局部變量,可能線程執行時該局部變量已經被銷毀瞭,而 final 類型的局部變量在 Lambda 表達式(匿名類) 中其實是局部變量的一個拷貝。
在java編譯時,匿名內部類也會被當作普通的類處理,隻不過編譯器生成它構造方法的時候,除瞭將外部類的引用傳遞瞭過來,還將基本數據類型的變量復制瞭一份過來,並把引用數據類型的變量引用也傳遞瞭過來。因此,基本數據類型的變量當然不能修改瞭,不然就會跟外部的變量產生不一致,這樣的話變量的傳遞也就變得毫無意義瞭。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- java中lambda(函數式編程)一行解決foreach循環問題
- 詳解Java8的forEach(…)如何提供index值
- java8保姆級lambda表達式教程
- 詳解Java中String,StringBuffer和StringBuilder的使用
- Java中forEach使用lambda表達式,數組和集合的區別說明