Java中l(wèi)ist.foreach不能使用字符串拼接的問(wèn)題
list.foreach不能使用字符串拼接
如圖,不能使用String進(jìn)行拼接
因?yàn)長(zhǎng)ambda的本質(zhì)實(shí)際上是匿名內(nèi)部類(lèi),所以t必須是final類(lèi)型(不過(guò)代碼中的final可以省略),是不可以重新賦值的。
可以使用
final StringBuilder str = new StringBuilder("已選擇:");
如圖二
foreach循環(huán)中不能使用字符串拼接
問(wèn)題
@Test public void forEachTest(){ String str = "中國(guó)你好!"; List<String> list = Arrays.asList("a","b","c","d"); list.forEach(item->{ //編輯錯(cuò)誤:Variable used in lambda expression should be final or effectively final str += item; }); //可以使用增強(qiáng)for // for (String item : list) { // str += item; // } System.out.println("結(jié)果:" + str); }
該編譯不通過(guò)的根本原因:Lambda表達(dá)式中的局部變量要使用final的問(wèn)題。
因?yàn)镾tring類(lèi)型屬于引用數(shù)據(jù)類(lèi)型,String字符串有不可變的特性,String在進(jìn)行字符串拼接時(shí),每次都會(huì)指向不同的地址值,因此str變量不能被看作是一個(gè)final類(lèi)型,也就不符合Lambda表達(dá)式的使用要求。
解決
使用StringBuffer或StringBuilder:
@Test public void forEachTest(){ //String str = "中國(guó)你好!"; List<String> list = Arrays.asList("a","b","c","d"); StringBuffer stringbuffer = new StringBuffer("中國(guó)你好!"); list.forEach(item->{ stringbuffer .append(item); }); //可以使用增強(qiáng)for // for (String item : list) { // str += item; // } System.out.println("結(jié)果:" + sb); }
原理
StringBuffer是一個(gè)引用數(shù)據(jù)類(lèi)型,在進(jìn)行append()時(shí),只是修改了內(nèi)容,并沒(méi)有改變地址值,這個(gè)stringbuffer變量就在編譯時(shí)看成了final類(lèi)型的變量,因此可以使用。
Lambda表達(dá)式中的局部變量要使用final的問(wèn)題
lambda表達(dá)式使用局部變量要用final
lambda表達(dá)式本身是一個(gè)匿名內(nèi)部類(lèi)的一種編寫(xiě)形式,可以操作外部的變量
使用實(shí)例變量或靜態(tài)變量是沒(méi)有限制的(可認(rèn)為是通過(guò) final 類(lèi)型的局部變量 this 來(lái)引用前兩者)
使用局部變量必須顯式的聲明為 final 或?qū)嶋H效果的的 final 類(lèi)型,即該變量從未被改變過(guò)
@Test public void finalTest(){ String str = "中國(guó)你好!"; //在Lambda中使用該變量,該變量不能被修改過(guò),java8會(huì)默認(rèn)加上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("結(jié)果:" + collect); //不能改變str,否則Lambda表達(dá)式中編譯失敗 //str = "山東你好"; }
一個(gè)局部變量如果要在匿名類(lèi)或是 Lambda 表達(dá)式中訪(fǎng)問(wèn),那么這個(gè)局部變量必須是 final 的,即使沒(méi)有修飾為 final 類(lèi)型,編譯器也會(huì)自動(dòng)加上 final 修飾符。
在 Java 8 下,即使局部變量未聲明為 final 類(lèi)型,一旦在 Lambda 表達(dá)式(匿名類(lèi)) 中使用,就被強(qiáng)型加上了 final 屬性,所以后面就無(wú)法再次給 str 賦值了。
為什么 Lambda 表達(dá)式(匿名類(lèi)) 不能訪(fǎng)問(wèn)非 final 的局部變量呢?
因?yàn)閷?shí)例變量存在堆中,而局部變量是在棧上分配,Lambda 表達(dá)式(匿名類(lèi)) 會(huì)在另一個(gè)線(xiàn)程中執(zhí)行。如果在線(xiàn)程中要直接訪(fǎng)問(wèn)一個(gè)局部變量,可能線(xiàn)程執(zhí)行時(shí)該局部變量已經(jīng)被銷(xiāo)毀了,而 final 類(lèi)型的局部變量在 Lambda 表達(dá)式(匿名類(lèi)) 中其實(shí)是局部變量的一個(gè)拷貝。
在java編譯時(shí),匿名內(nèi)部類(lèi)也會(huì)被當(dāng)作普通的類(lèi)處理,只不過(guò)編譯器生成它構(gòu)造方法的時(shí)候,除了將外部類(lèi)的引用傳遞了過(guò)來(lái),還將基本數(shù)據(jù)類(lèi)型的變量復(fù)制了一份過(guò)來(lái),并把引用數(shù)據(jù)類(lèi)型的變量引用也傳遞了過(guò)來(lái)。因此,基本數(shù)據(jù)類(lèi)型的變量當(dāng)然不能修改了,不然就會(huì)跟外部的變量產(chǎn)生不一致,這樣的話(huà)變量的傳遞也就變得毫無(wú)意義了。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決maven啟動(dòng)Spring項(xiàng)目報(bào)錯(cuò)的問(wèn)題
下面小編就為大家分享一篇解決maven啟動(dòng)Spring項(xiàng)目報(bào)錯(cuò)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12java新特性之for循環(huán)最全的用法總結(jié)
下面小編就為大家?guī)?lái)一篇java新特性之for循環(huán)最全的用法總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12SpringBoot實(shí)現(xiàn)配置文件的替換
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)配置文件的替換,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java如何實(shí)現(xiàn)讀取txt文件內(nèi)容并生成Word文檔
本文主要介紹了通過(guò)Java實(shí)現(xiàn)讀取txt文件中的內(nèi)容,并將內(nèi)容生成Word文檔。文章的代碼非常詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2021-12-12java String 轉(zhuǎn)成Double二維數(shù)組的方法
下面小編就為大家?guī)?lái)一篇java String 轉(zhuǎn)成Double二維數(shù)組的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10java.lang.ExceptionInInitializerError初始化程序中的異常錯(cuò)誤的解決
java.lang.ExceptionInInitializerError?異常在?Java?中表示一個(gè)錯(cuò)誤,該錯(cuò)誤發(fā)生在嘗試初始化一個(gè)類(lèi)的靜態(tài)變量、靜態(tài)代碼塊或枚舉常量時(shí),本文就來(lái)介紹并解決一下,感興趣的可以了解一下2024-05-05