面試題:Iterator遍歷的新增刪除
阿新 • • 發佈:2019-01-03
list是一個ArrayList的物件,哪個選項的程式碼填到//todo delete處,可以在Iterator遍歷的過程中正確並安全的刪除一個list中儲存的物件?()
Iterator it = list.iterator();
int index = 0;
while (it.hasNext())
{
Object obj = it.next();
if (needDelete(obj)) //needDelete返回boolean,決定是否要刪除
{
//todo delete
}
index ++;
}
it.remove(); √
list.remove (obj); ×
list.remove(index); ×
list.remove(obj,index); ×
如果在迴圈的過程中呼叫集合的remove()方法,就會導致迴圈出錯,例如:
for(int i=0;i<list.size();i++){
list.remove(...);
}
迴圈過程中list.size()的大小變化了,就導致了錯誤。
所以,如果你想在迴圈語句中刪除集合中的某個元素,就要用迭代器iterator的remove()方法,因為它的remove()方法不僅會刪除元素,還會維護一個標誌,用來記錄目前是不是可刪除狀態,例如,你不能連續兩次呼叫它的remove()方法,呼叫之前至少有一次next()方法的呼叫。
原始碼是這麼描述的:ArrayList 繼承了 AbstractList, 其中AbstractList 中有個modCount 代表了集合修改的次數。在ArrayList的iterator方法中會判斷 expectedModCount與 modCount是否相等,如果相等繼續執行,不相等報錯,只有iterator的remove方法會在呼叫自身的remove之後讓 expectedModCount與modCount再相等,所以是安全的。
在使用set/map時,一個可愛的小bug:java.util.ConcurrentModificationException
【錯誤場景1】:set容器,邊遍歷,邊add/remove元素
Set<String> set = new HashSet<String>();
for (int i = 0; i < 10000; i++) {
set.add(Integer.toString(i));
}
for (String str : set) { //或使用iterator來迴圈,JDK5.0以上,這樣的遍歷底層也都是iterator實現。
set.add("xxx"); //報錯
//set.remove(str); //報錯
}
【錯誤場景2】:map容器,邊遍歷,邊remove元素
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < 100; i++) {
map.put(Integer.toString(i), Integer.toString(i));
}
for (String str : map.keySet()) {//或使用iterator來迴圈
map.remove(str); //報錯
}
【錯誤場景3】list容器,邊遍歷,邊add/remove元素
List<String> list = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
list.add(Integer.toString(i));
}
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String val = it.next();
if (val.equals("5")) {
list.add(val); //報錯
//list.remove(val); //報錯
}
}
【錯誤原因】
【解決辦法】
【正確使用案例】
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String val = it.next();
if (val.equals("5")) {
it.remove();
}
}
List<String> newList = new ArrayList<String>();
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String val = it.next();
if (val.equals("5")) {
newList.add(val);
}
}
list.addAll(newList);