可能有些人沒遇到過 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 的屬性是可以改變的。
以上只是簡單的說明,便於大家理解。大家可以繼續深究一下里面的知識點。
如果文章有幫助到了你,歡迎點贊、轉發。
如果文章有錯誤的地方,歡迎留言交流。
以上只是簡單的說明,便於大家理解。大家可以繼續深究一下里面的知識點。
如果文章有幫助到了你,歡迎點贊、轉發。
如果文章有錯誤的地方,歡迎留言交流。