AIブログ エラーの対処方法

【Java】ConcurrentModificationExceptionの発生原因と対処方法 5つの発生原因と対処方法を確認して、適切に対処しよう!

この記事は90%~100%ChatGPTで作られています。

作り方はこちらをクリック

このブログではAffinger5を使用しています。

ブログテーマが気に入った方はコチラをクリック

JavaのConcurrentModificationExceptionとは

Javaでコレクション(リスト、セット、マップなど)を操作する際に、イテレーション中にコレクションが変更されるとConcurrentModificationExceptionが発生します。
これは、イテレータがコレクションを走査している間に他のスレッドからそのコレクションが変更されると、予期せぬ結果を招く可能性があるため、Javaではこれを防ぐための仕組みとしてConcurrentModificationExceptionが設けられています。

サルモリ
それじゃあ、具体的なエラーが発生するソースコードとその対処方法を見ていくよ!

エラーケース1: イテレーション中のリスト変更

最も一般的な例は、for-eachループを使用してリストをイテレートしながらリスト自体を変更しようとする場合です。
以下にそのようなソースコードを示します。

エラーが発生するソースコード

 出力結果
Exception in thread "main" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996) at Main.main(Main.java:11) 

このソースコードでは、リストをイテレートしながらリストから要素を削除しようとしています。
この操作は、イテレータがリストの構造を保証できないため、ConcurrentModificationExceptionを引き起こします。

サルモリ
でも安心して!この問題は解決できるよ!

対処法1: Iteratorを使用する

この問題を解決する一つの方法は、Iteratorを使用することです。
Iteratorのremoveメソッドを使用すれば、イテレーション中に安全にコレクションを変更することができます。以下に修正後のソースコードを示します。

対処後のソースコード

 出力結果
(エラーなし) 

このソースコードでは、Iteratorのremoveメソッドを使用してリストから要素を削除しています。
Iteratorのremoveメソッドは、イテレータが指している要素を安全に削除します。
したがって、このコードはConcurrentModificationExceptionを引き起こしません。

サルモリ
次のエラーケースに進もう!

エラーケース2: マルチスレッド環境

マルチスレッド環境では、一つのスレッドがコレクションをイテレートしている間に、別のスレッドがコレクションを変更するとConcurrentModificationExceptionが発生します。
以下にそのようなソースコードを示します。

エラーが発生するソースコード

 出力結果
Exception in thread "Thread-0" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996) at Main.lambda$main$0(Main.java:12) at java.base/java.lang.Thread.run(Thread.java:834) 

このソースコードでは、一つのスレッドがリストをイテレートしている間に、別のスレッドがリストに新しい要素を追加しています。
これにより、イテレーション中にリストの構造が変わるため、ConcurrentModificationExceptionが発生します。

サルモリ
でも、マルチスレッド環境でも安全にコレクションを操作する方法があるよ!

対処法2: 同期化されたコレクションを使用する

この問題を解決する方法の一つは、同期化されたコレクションを使用することです。
同期化されたコレクションは、一度に一つのスレッドのみがアクセスできるようにロックを提供します。
Javaでは、CollectionsクラスのsynchronizedListメソッドを使用して同期化されたリストを作成することができます。
以下に修正後のソースコードを示します。

対処後のソースコード

 出力結果
(エラーなし) 

このソースコードでは、Collections.synchronizedListメソッドを使用して同期化されたリストを作成しています。
また、イテレーションは同期化されたブロック内で行われ、これによりリストに対する同時アクセスが防がれます。
したがって、このコードはConcurrentModificationExceptionを引き起こしません。

サルモリ
さて、次のエラーケースに進もう!

エラーケース3: Stream APIと並列処理

Java 8のStream APIを使用して並列処理を行う際にも、注意が必要です。
以下のソースコードは、並列ストリームを使用してリストの各要素を削除しようとしています。
しかし、これはConcurrentModificationExceptionを引き起こします。

エラーが発生するソースコード

 出力結果
Exception in thread "main" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996) at java.base/java.util.AbstractCollection.remove(AbstractCollection.java:305) at Main.lambda$main$0(Main.java:10) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) at Main.main(Main.java:10) 

このソースコードでは、parallelStreamメソッドを使用してリストの並列ストリームを取得し、forEachメソッドを使用して各要素を削除しようとしています。
しかし、並列ストリームを使用すると、複数のスレッドがリストを同時に変更しようとするため、ConcurrentModificationExceptionが発生します。

サルモリ
並列ストリームでも安全にリストを操作するにはどうすればいいんだろう?

対処法3: ストリーム操作を適切に使用する

この問題を解決するには、ストリーム操作を適切に使用する必要があります。
具体的には、forEachメソッドではなく、filterメソッドとcollectメソッドを使用して、削除したい要素を除外する新しいリストを作成することができます。
以下に修正後のソースコードを示します。

対処後のソースコード

 出力結果
(エラーなし) 

このソースコードでは、filterメソッドを使用して"Two"と等しくない要素だけを含む新しいリストを作成しています。
この方法であれば、リストの変更が同時に行われることはなく、ConcurrentModificationExceptionを回避することができます。

サルモリ
次のエラーケースに進もう!

エラーケース4: Iteratorのremoveメソッド

Javaでは、Iteratorを使用してコレクションを反復処理することができます。
しかし、Iteratorのremoveメソッドを使用して要素を削除する際にも、注意が必要です。
以下のソースコードは、Iteratorのremoveメソッドを使用せずにリストの要素を削除しようとしています。
これはConcurrentModificationExceptionを引き起こします。

エラーが発生するソースコード

 出力結果
Exception in thread "main" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1042) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:996) at Main.main(Main.java:13) 

このソースコードでは、Iteratorを使用してリストを反復処理し、"Two"と等しい要素をリストから直接削除しようとしています。
しかし、これはリストの構造を変更するため、ConcurrentModificationExceptionが発生します。

サルモリ
Iteratorを使って要素を削除する正しい方法を見てみよう!

対処法4: Iteratorのremoveメソッドを使用する

この問題を解決するには、Iteratorのremoveメソッドを使用する必要があります。
Iteratorのremoveメソッドは、反復処理中のコレクションから安全に要素を削除するためのものです。
以下に修正後のソースコードを示します。

対処後のソースコード

 出力結果
(エラーなし) 

このソースコードでは、Iteratorのremoveメソッドを使用して"Two"と等しい要素を安全に削除しています。
この方法であれば、反復処理中にリストの構造を変更しても、ConcurrentModificationExceptionを回避することができます。

サルモリ
最後のエラーケースに進もう!

エラーケース5: サブリストを変更する

Javaでは、ListのsubListメソッドを使用してリストの一部を切り出すことができます。
しかし、このサブリストを変更すると、元のリストも影響を受けます。
そして、元のリストとサブリストを同時に変更しようとすると、ConcurrentModificationExceptionが発生します。
以下のソースコードは、サブリストを変更しようとしています。

エラーが発生するソースコード

 出力結果
Exception in thread "main" java.util.ConcurrentModificationException at java.base/java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1351) at java.base/java.util.ArrayList$SubList.clear(ArrayList.java:1296) at Main.main(Main.java:12) 

このソースコードでは、subListメソッドを使用して元のリストからサブリストを作成し、その後で元のリストとサブリストを同時に変更しようとしています。
これにより、リストの構造が同時に変更されるため、ConcurrentModificationExceptionが発生します。

サルモリ
この問題を解決する方法はないのかな?

対処法5: サブリストを新しいリストとして作成する

この問題を解決するには、サブリストを新しいリストとして作成する必要があります。
これにより、サブリストの変更が元のリストに影響を及ぼすことはありません。
以下に修正後のソースコードを示します。

対処後のソースコード

 出力結果
(エラーなし) 

このソースコードでは、新しいArrayListのインスタンスを作成してサブリストを生成しています。
これにより、サブリストの変更が元のリストに影響を及ぼさないため、ConcurrentModificationExceptionを回避できます。

サルモリ
これで全てのエラーケースを見ることができたね!

まとめ

Javaでリストを反復処理中にリストの構造を変更しようとすると、ConcurrentModificationExceptionが発生する可能性があります。
このエラーを回避するためには、反復処理とリストの構造の変更を分離するか、Iteratorのremoveメソッドや、Stream APIのfilterメソッドなど、反復処理中にリストの構造を安全に変更する方法を使用する必要があります。
また、サブリストを変更する場合は、新しいリストとして作成することで元のリストに影響を及ぼさないようにすることが重要です。
これらの方法を理解し、適切に使用することで、Javaのリスト操作をより安全に、効率的に行うことができます。

サルモリ
Javaのリスト操作は慎重に行う必要があるね。
エラーが出た時は、ここで学んだ方法を思い出して対処してみてほしいな!

最後まで読んで頂き、ありがとうございました。少しでもお役にたてたなら幸いです!

サルモリ
最後まで読んでくれてありがとう!!

この記事は90%~100%ChatGPTで作られています。

作り方はこちらをクリック

-AIブログ, エラーの対処方法

Ads Blocker Image Powered by Code Help Pro

広告ブロックを検出しました。

ブラウザの広告機能を使用して広告をブロックしていることが検出されました。
ブラウザの広告ブロッカーを無効にし、「更新」をクリックしてください。

Powered By
Best Wordpress Adblock Detecting Plugin | CHP Adblock