1.問題
我們經常會遍歷 list集合,在遍歷的過程中,如果在遍歷的過程中添加了 add() 或者 addAll() 方法修改了遍歷的list列表,那么會報錯.
代碼演示:
List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); for(int i = 0;i<list.size();i++){ System.out.println(i); }
這段代碼的結果大家都知道, 0 1 2;
但是如果在遍歷的過程中修改了list 的內容
List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); for(int i = 0;i<list.size();i++){ System.out.println(i); list.add(4); }
那么就會出現死循環,原因是list實現是數組,list.size() 在add之后 size() 會增加,也就是說 list的下標一直在增加, list.size()的值也一直在增加,所以出現了死循環.addAll()方法同理
而且jdk文檔也已經說明了這一點:
添加指定 collection 中的所有元素到此列表的結尾,順序是指定 collection 的迭代器返回這些元素的順序(可選操作)。如果在操作正在進行中修改了指定的 collection,那么此操作的行為是不確定的(注意,如果指定的 collection 是此列表,並且它是非空的,則會發生這種情況。)
2.解決:
創建一個臨時list變量就可以解決.
List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); List<Object> temp = Arrays.asList(list.toArray()); for(int i = 0;i<temp.size();i++){ System.out.println(i); list.add(4); }
如圖,在遍歷前創建一個temp變量即可. 注意:因為toArray()方法返回的是Object類型,所以只能創建List<Object>,大家有更好的解決可以和我交流交流.
附上剛剛完成的代碼,用遞歸實現遍歷樹狀圖;
//遞歸獲取架構下級id private static List<Integer> selectAllStructLowLevelIdById(List<Integer> list) { if(list == null || list.isEmpty()){ return list; }else{ //創建臨時變量,用來遍歷 List<Object> template = Arrays.asList(list.toArray()); for(int i = 0;i<template.size();i++){ List<Integer> ids = attendanceMapper.selectStructLowLevelIdById((Integer)template.get(i)); list.addAll(selectAllStructLowLevelIdById(ids)); } return list; } }
數學真是偉大.