Listコレクション削除要素の正しい姿勢
25870 ワード
一、集合要素遍歴
集合を巡回する場合、ビジネスのニーズに応じて集合の要素を排除する必要がある場合があります.通常、リスト集合を巡回するには、次の3つの方法が一般的です.
上の3つの方法を総合して削除をテストします.コードは以下の通りです.
コンソール出力の結果を見てみましょう.
>通常for削除:削除OK>強化for削除:削除時に例外を投げ出す
四、異常探究
なぜ増強forサイクルを使用するとこの異常が放出されるのか.まず、強化for遍歴コンパイル後のコードを見てみましょう.対応する
もともと私たちの反復器は、コンパイル後、jvmもそれを反復器を使って遍歴するように翻訳しました.では、反復器が遍歴したときに何か要求があったのではないかと疑うことができます.
上記の方法の1つである
modCountはlist集合の修正回数を表し、expectedModCountは合理的な操作時の期限切れの修正回数である.通常動作時modCount=expectedModCount
**理由:**
反復器のremoveメソッドは
反復器のremove()メソッドを使用して、集合要素の削除操作を推奨します.
集合を巡回する場合、ビジネスのニーズに応じて集合の要素を排除する必要がある場合があります.通常、リスト集合を巡回するには、次の3つの方法が一般的です.
1. for
for(int i= 0; i<list.size(); i++) {
}
2. for
for(int i : list){
}
3.
Iterator <Integer> iterator = list.iterator();
while (iterator.hasNext()){}
二、集合要素の削除
上の3つの方法を総合して削除をテストします.コードは以下の通りです.
@Test
public void test3(){
try {
delete1();
}catch (Exception e){
log.info("delete1 , {}",e.getClass().getSimpleName());
}
try {
delete2();
}catch (Exception e){
log.info("delete2 , {}",e.getClass().getSimpleName());
}
try {
delete3();
}catch (Exception e){
log.info("delete3 , {}",e.getClass().getSimpleName());
}
}
// list
public List<Integer> init(){
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
return list;
}
// for
public <T> void delete1(){
List<Integer> list = init();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(3)){
list.remove(i);
}
}
log.info("delete1 ");
}
//
public void delete2(){
List<Integer> list = init();
Iterator <Integer> iterator = list.iterator();
while (iterator.hasNext()){
Integer next = iterator.next();
if (next.equals(3)) {
iterator.remove();
}
}
log.info("delete2 ");
}
// for
public void delete3(){
List<Integer> list = init();
for (Integer t : list) {
if (t.equals(3)) {
list.remove(t);
}
}
log.info("delete3 ");
}
コンソール出力の結果を見てみましょう.
21:03:01.697 [main] INFO com.kuake.concurrent.DemoTest - delete1
21:03:01.701 [main] INFO com.kuake.concurrent.DemoTest - delete2
21:03:01.701 [main] INFO com.kuake.concurrent.DemoTest - delete3 , ConcurrentModificationException
三、テスト結果
>通常for削除:削除OK>強化for削除:削除時に例外を投げ出す
ConcurrentModificationException
>反復器削除:削除OK四、異常探究
なぜ増強forサイクルを使用するとこの異常が放出されるのか.まず、強化for遍歴コンパイル後のコードを見てみましょう.対応する
class
ファイルをideaで見つけます. public void delete3() {
List<Integer> list = this.init();
Iterator var2 = list.iterator();
while(var2.hasNext()) {
Integer t = (Integer)var2.next();
if (t.equals(3)) {
list.remove(t);
}
}
log.info("delete3 ");
}
もともと私たちの反復器は、コンパイル後、jvmもそれを反復器を使って遍歴するように翻訳しました.では、反復器が遍歴したときに何か要求があったのではないかと疑うことができます.
ArrayList
の反復器ソースコードを参照すると、次のコードが表示されます.コードの断片は以下の通りです.これは彼のnext()
の方法です. public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
上記の方法の1つである
checkForComodification()
コードは以下の通りである. final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
modCountはlist集合の修正回数を表し、expectedModCountは合理的な操作時の期限切れの修正回数である.通常動作時modCount=expectedModCount
**理由:**
list.remove()
メソッドがmodCount++を操作するためです.expectedModCountは元の値を保存します.その後、反復器のnext()操作を実行すると、上記の異常が放出されます.五、反復器のremove()方法
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
反復器のremoveメソッドは
expectedModCount = modCount
操作を実行します.したがって,next()メソッドを次回実行すると異常は放出されない.六、まとめ
反復器のremove()メソッドを使用して、集合要素の削除操作を推奨します.