簡單說明:list.forEach 中變量必須為 final 的問題


可能有些人沒遇到過 list.forEach 中變量必須為 final 的問題,那就先舉兩個例子

示例1,如下:

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    int i = 0;
    stringList.forEach(s -> {
        System.out.println(s + i);
    });
}

示例2,如下:

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    int i = 0;
    stringList.forEach(s -> {
        System.out.println(s + i);
        // 示例1與示例2的區別
        i = i + 1
    });
}

咋一看,兩個示例沒什么問題,都能正常運行。但是實際運行結果如下。

示例1運行結果

a0
b0
c0
d0

而示例2無法運行,編輯器給了如下提示

Error:(16, 36) java: 從lambda 表達式引用的本地變量必須是最終變量或實際上的最終變量

要把示例2修正為可以運行的代碼,可以做如下修正:

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    final int[] i = {0};
    stringList.forEach(s -> {
        System.out.println(s + i[0]);
        i[0] = i[0] + 1;
    });
}

就以上的現象,用三個問題來簡單說明。

問題一,為什么示例2的 int i = 0 必須用 final 修飾?

答:forEach 在此處使用的是 lambda 表達式,可以簡單的把 lambda 表達式 理解為匿名內部類(lambda 表達式不僅僅是內部類這么簡單)。而匿名內部類的變量必須用 final 修飾。

問題二,為什么匿名內部類的變量必須用 final 修飾?

答:類的生命周期比方法的生命周期長,同理匿名類的生命周期比方法的生命周期長。換句話說,方法運行完了,變量釋放了,但是匿名內部類還在。這時就要求匿名內部類引用的變量必須還在,這樣才能保持數據的一致性。

問題三,為什么變量 int i 要改為數組 int[] i?

答:因為 final int i 中,i 的值是無法改變的,但是方法中需要一個可以改變的變量。在 final int[] i 中,i 的引用地址是不變的,但是 i 的屬性是可以改變的。

以上只是簡單的說明,便於大家理解。大家可以繼續深究一下里面的知識點。


如果文章有幫助到了你,歡迎點贊、轉發。

如果文章有錯誤的地方,歡迎留言交流。

以上只是簡單的說明,便於大家理解。大家可以繼續深究一下里面的知識點。


如果文章有幫助到了你,歡迎點贊、轉發。

如果文章有錯誤的地方,歡迎留言交流。

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM