2012-12-11 113 views
2

需要一些關於java.util.list的說明。我正在使用eclipse進行開發。
我寫了這個代碼需要關於java.util.list的一些說明

public static void main(String[] asdf){ 
     List<Integer> lst = new ArrayList<Integer>(); 
     for(int i=0;i<10000;i++){ 
      lst.add(i); 
     } 

     System.out.println(lst.size()); 

     for(int i=0;i<10000;i++){ 
      if((i%50)==0){ 
       lst.remove(i); 
      }   
     } 
     System.out.println(lst.size()); 

    } 

但是當我運行這段代碼它給例外

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 9850, Size: 9803 
    at java.util.ArrayList.rangeCheck(ArrayList.java:604) 
    at java.util.ArrayList.remove(ArrayList.java:445) 
    at com.ilex.reports.action.rpt.CNSReports.main(CNSReports.java:301) 

多了一個這個要注意的是 enter image description here

然後我做的代碼,即迭代的一個變化第二循環直到5000只,它工作正常

enter image description here

問題是 爲什麼給IndexOutOfBoundsException?

什麼是modCoutn?

做這件事的任何成爲內存的原因如果是的話泄漏如何解決它?

在此先感謝。

+2

加上將它聲明爲列表的點。儘管使用迭代器遍歷它通常會更好。 – BevynQ

+0

@shah看看我的答案,可能這是你真正想要的嗎? – kornero

回答

16

從列表中刪除元素使其更小。你的第二個循環運行到10000,但是到達那裏的時候,列表會縮小到不到10000。事實上,如果你的意圖是刪除所有50的倍數,你可以從10000向後循環到0,步長爲50,避免這個問題,並且速度更快。

for (int i=9950; i>=0; i-=50){ 
    lst.remove(i); 
} 

注意,目前的方法,如果你的目的是去除50的倍數,是行不通的,因爲之後的第一個刪除不變,每個索引處的值是索引,不再成立。

modCount是一個內部變量,ArrayList用來檢測它是否參照其上的任何迭代器進行更改。它基本上統計對列表的所有修改。迭代器保留自己的計數,並檢查它是否與列表保持同步。

您的代碼不會導致任何內存泄漏。在java內存'泄漏',如果不再使用的對象仍然被引用,所以他們不能被垃圾收集。但是由於示例中的所有內容都在方法範圍之外傳遞,所以一旦方法被留下,所有內容都可以被使用。 (因爲它是主要方法,vm將停止運行並釋放其內存)

+0

謝謝你的答案...你能解釋一下更多的內存泄漏 – NoNaMe

+0

我只能輸入這麼快:)編輯應該也有代碼完成。 – bowmore

+0

對不起打擾你...我以爲你已經做了答案,再次感謝你的好和完整的答案:) – NoNaMe

1

當您刪除列表中的元素時,列表大小變得更小。

1
List<Integer> removeElements = new ArrayList<Integer>(); 
for(int i=0;i<10000;i++){ 
      if((i%50)==0){ 
       removeElements.add(lst.get(i)); 
      }   
     } 

lst.removeAll(removeElements); 

這是爲了做到這一點

關於內存泄漏的更安全的方式:

這裏你不必擔心內存泄漏,當引用卡住長於需要做會發生內存泄漏沒有收集垃圾。這通常是由於靜態引用

1

你可能想這樣做:

for(int i=0;i<10000;i++){ 
     if((i%50)==0){ 
      lst.remove(Integer.valueof(i)); 
     }   
    } 

列表中包含了2種remove方法,通過索引和對象。 你的列表中包含的對象,您加入到它的一些「INT I」(原始),但編譯器自動裝箱替換爲:

Integer.valueof(i) 

所以,當你刪除,您可以通過刪除對象,而是通過索引。

例如,你有列表:{3,2,1}

當調用:

  • 刪除(0),列表成爲:{2,1} //按id除去
  • 刪除(1),列表成爲:{3,1} //按id除去
  • 刪除(Integer.valueof(1)),則列表成爲:{3,2} //由對象除去
3

列表不是一個數組,即使一個ArrayList支持一個數組。

intArray[i] = null; 

是不一樣的

arrayList.remove(i); 

在第二個(使用ArrayList),實際上是轉移所有元素i+1和高達向下,從而降低你的列表的大小。

如果需要從列表中刪除元素,從你,你正在做一個迭代,您可以使用Iterator

Iterator<Integer> iterator = list.iterator(); 
int i = 0; 
while (iterator.hasNext()) { 
    iterator.next(); // consume current item 
    if ((i++ % 50) == 0) { 
     iterator.remove(); 
    } 
} 

或者你可以使用這個哈克黑客

for(int i=0, len=lst.size();i<len;i++){ 
    if((i%50)==0){ 
     lst.remove(i); 
     len--; // decrease size of upper bound check 
    }   
} 

// or better... 
for (int len=lst.size() - 1, i=len - (len % 50); i>=0; i-=50){ 
    lst.remove(i); 
} 

...但迭代器的解決方案是你應該如何處理這種情況通常如何步驟通過Collection

modCount遞增每次addremove元素在你的ListArrayList)。這很重要,因爲當你迭代你的元素時,你不想「錯過」或者中途有其他改變元素的東西。 (這在多線程應用程序中尤其如此。)因此,如果某個進程在使用迭代器時修改了您的ArrayList,則會得到一個ConcurrentModificationException警告您自創建迭代器後列表已更改。 (請參閱列表iterator()

最後,對於最後一個問題,除非列表元素在其他地方引用,否則不應該關注內存泄漏和ArrayList。在Java中,只要對象沒有被其他對象引用,它就是garbage collection的候選對象。

+0

在迭代器中移除方法是可選的,許多列表不支持它。 – kornero

+0

@ kornero,其他列表實現不在問題中討論。並且可以將不支持的迭代器實現封裝到支持它的不同集合中,或者使用輔助列表來存儲要刪除的所有元素。 ......但這正在進入猜測並超出問題的範圍。 :) –

0

第一點:在要刪除列表中的元素的這部分代碼見:

for(int i=0;i<10000;i++){ 
      if((i%50)==0){ 
       lst.remove(i); 
      }   
     } 

這就是爲什麼你的列表的大小被還原了,你會得到錯誤即java.lang.IndexOutOfBoundsException

第二點:modCount看起來像列表中的eclipse的內部計數。 第三點:這不會成爲內存泄漏的原因,因爲列表大小正在減少。

希望這會幫助你。