A ConcurrentModificationException elkerülése a Java-ban

1. Bemutatkozás

Ebben a cikkben megnézzük a ConcurrentModificationException osztály.

Először magyarázatot adunk a működésére, majd bebizonyítjuk a kiváltó teszt segítségével.

Végül kipróbálunk néhány megoldást gyakorlati példák segítségével.

2. Kiváltás a ConcurrentModificationException

Lényegében a ConcurrentModificationException régebben kudarcot okoz, ha módosul valami, amit iterálunk. Bizonyítsuk be ezt egy egyszerű teszttel:

A @Test (várható = ConcurrentModificationException.class) public void míg aRemovingDuringIteration_shouldThrowException () dobja az InterruptedException {List integers = newArrayList (1, 2, 3); for (Egész egész szám: egész szám) {integers.remove (1); }}

Mint láthatjuk, az iteráció befejezése előtt eltávolítunk egy elemet. Ez váltja ki a kivételt.

3. Megoldások

Előfordulhat, hogy iterálás közben valóban el akarjuk távolítani az elemeket a gyűjteményből. Ha ez a helyzet, akkor van néhány megoldás.

3.1. Iterátor közvetlen használata

A az egyes hurok egy Iterátor a színfalak mögött, de kevésbé bőbeszédű. Ha azonban az előző tesztünket átalakítottuk egy Iterátor, további módszerekhez férhetünk hozzá, mint pl távolítsa el (). Próbáljuk meg inkább ezt a módszert használni a listánk módosításához:

mert (Iterator iterator = integers.iterator (); iterator.hasNext ();) {Integer integer = iterator.next (); if (egész = = 2) {iterator.remove (); }}

Most észrevesszük, hogy nincs kivétel. Ennek oka, hogy a eltávolítás () módszer nem okoz a ConcurrentModificationException. Iterálás közben biztonságos a telefonálás.

3.2. Nem távolítható el az iteráció során

Ha meg akarjuk tartani a magunkat az egyes hurok, akkor tudjuk. Csak annyit kell várnunk az iteráció után, hogy eltávolítsuk az elemeket. Próbáljuk ki úgy, hogy hozzáadjuk az eltávolítandó elemeket az a-hoz eltávolítani listázzuk iterálás közben:

Lista egészek = newArrayList (1, 2, 3); List toRemove = newArrayList (); for (Egész egész szám: egész szám) {if (egész = = 2) {toRemove.add (egész); }} integers.removeAll (toRemove); assertThat (egész számok) .conactExactly (1, 3); 

Ez egy másik hatékony módszer a probléma kiküszöbölésére.

3.3. Használata removeIf ()

A Java 8 bemutatta a removeIf () módszer a Gyűjtemény felület. Ez azt jelenti, hogy ha dolgozunk vele, akkor a funkcionális programozás ötleteit felhasználhatjuk ugyanazok az eredmények elérésére:

Lista egészek = newArrayList (1, 2, 3); egészek.removeIf (i -> i == 2); assertThat (egész számok) .conactExactly (1, 3);

Ez a kijelentő stílus kínál számunkra a legkevésbé bőbeszédet. A felhasználási esettől függően azonban más módszereket találhatunk kényelmesebbnek.

3.4. Szűrés adatfolyamok használatával

Ha belemerülünk a funkcionális / deklaratív programozás világába, megfeledkezhetünk a gyűjtemények mutációjáról, ehelyett azokra az elemekre összpontosíthatunk, amelyeket valóban feldolgozni kellene:

Gyűjtemény egész számai = newArrayList (1, 2, 3); Összegyűjtött lista = egész számok .stream () .filter (i -> i! = 2) .map (Object :: toString) .collect (toList ()); assertThat (összegyűjtött) .conactExactly ("1", "3");

Megtettük az előző példánk inverzét, és állítmányt adtunk az elemek meghatározására, amelyek tartalmazzák, nem pedig kizárják. Előnye, hogy az eltávolítás mellett más funkciókat is összekapcsolhatunk. A példában egy függvényt használunk térkép(), de még több műveletet is használhat, ha akarjuk.

4. Következtetés

Ebben a cikkben bemutattuk azokat a problémákat, amelyekkel szembesülhet, ha elemeket távolít el a gyűjteményből az ismétlés közben, és néhány megoldást is nyújtottunk a probléma elvetésére.

Ezeknek a példáknak a megvalósítása megtalálható a GitHub oldalon. Ez egy Maven projekt, ezért könnyen futtathatónak kell lennie.


$config[zx-auto] not found$config[zx-overlay] not found