GMOT
Nieuws:
 
*
Welkom, Gast. Alsjeblieft inloggen of registreren. 18 Maart 2019, 17:35:25


Login met gebruikersnaam, wachtwoord en sessielengte


Pagina's: [1]
  Print  
Advertenties


Maarten
Approaching infinity
********

Berichten: 8.271



Bekijk profiel
« Gepost op: 06 November 2015, 13:40:24 »

Ik heb een list die ik in de variabele drops zet. Met een for-loop kijk ik in alle waarden van drops of deze aan bepaalde voorwaarden voldoet. Als dit zo is moet deze specifieke drop uit de list verwijdert worden. Het probleem is dat ik dan een java.util.ConcurrentModificationException krijg.

Dit is de code:
Code:
List<ItemStack> drops = event.getDrops();
for (ItemStack drop : drops){
    if (...){
        event.getDrops().remove(drop);
    }
}

De manier waarop ik dit opgelost heb is door alle waarden van event.getDrops() één voor één in een ArrayList te zetten en hierover te loopen. De huidige code ziet er zo uit:
Code:
ArrayList<ItemStack> drops = new ArrayList<ItemStack>();

for (ItemStack s : event.getDrops()){
    drops.add(s);
}

for (ItemStack drop : drops){
    if (...){
        event.getDrops().remove(drop);
    }
}

Ik vind het zelf niet een erg mooie code. Daarom wil ik graag weten of er een betere manier is om dit te doen, zodat ik niet twee for-loops nodig heb.
Gelogd

djekkoo
Pretty addicted
*******

Berichten: 4.505


Bekijk profiel
« Antwoord #1 Gepost op: 06 November 2015, 13:58:09 »

Als je er met een Iterator overheen loopt kun je Iterator.remove() gebruiken. Smiley
Gelogd

Je hebt het recht brutaal te zijn, op voorwaarde dat je weet waarover je spreekt - Goethe

superice
Pretty addicted
*******

Berichten: 2.743


Genie in ruste.


Bekijk profiel WWW
« Antwoord #2 Gepost op: 06 November 2015, 14:28:39 »

Het probleem is dat je niet een lijst waar je overheen loopt kunt aanpassen zonder een iterator te gebruiken.

Wat misschien een betere oplossing is (in het kader van non-mutability) is een nieuwe lijst aanmaken waar je de dingen in stopt die je wilt houden.

Code:
List<ItemStack> drops = event.getDrops();
List<ItemStack> newDrops = new ArrayList<>();
for (ItemStack drop : drops) {
  if (!...) {
    newDrops.add(drop);
  }
}

Dit geeft alle voordelen van non-mutable code, zoals er van uit kunnen gaan dat je lijst niet aanpast, wat op zich voor je code in veel gevallen prettiger is.

Als je per se echt die instance van de lijst wilt gebruiken kun je inderdaad djekkoo's oplossing gebruiken.

Overigens, Java vangt dit af, maar in andere talen kunnen je lijsten aanpassen terwijl je er overheen loopt (JavaScript, PHP...). Als je dingen er uit wilt filteren is de makkelijke fix om er achterstevoren doorheen te loopen, zodat je niet de verkeerde elementen gaat verwijderen Smiley
Gelogd


Sunnywout
Infinity
*********

Berichten: 17.708


speel mijn game


Bekijk profiel WWW
« Antwoord #3 Gepost op: 06 November 2015, 15:28:39 »

Het is trouwens ook goed mogelijk dat .getDrops() niet telkens dezelfde variabele teruggeeft, bijvoorbeeld

Code:
ArrayList getDrops()
{
  ArrayList tmp = new ArrayList();
  ...
  return tmp;
}

Dan zou .remove() sowieso geen nut hebben Tongue.
Gelogd

shitposting is a lifestyle, not a disease

djekkoo
Pretty addicted
*******

Berichten: 4.505


Bekijk profiel
« Antwoord #4 Gepost op: 06 November 2015, 15:55:34 »

Maar een ArrayList is gewoon een mutable object waaraan hij dingen kan toevoegen, ergens in de code ervan uitgaan dat deze non-mutable is geeft een behoorlijke kans dat je later fouten introduceert. Lijkt me niet bepaald good practise, eerlijk gezegd.

In Java 8 hebben we tegenwoordig trouwens ook Collection.RemoveIf, superhandig! Smiley

https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-
Gelogd

Je hebt het recht brutaal te zijn, op voorwaarde dat je weet waarover je spreekt - Goethe

Maarten
Approaching infinity
********

Berichten: 8.271



Bekijk profiel
« Antwoord #5 Gepost op: 06 November 2015, 17:22:22 »

Het is trouwens ook goed mogelijk dat .getDrops() niet telkens dezelfde variabele teruggeeft, bijvoorbeeld

Code:
ArrayList getDrops()
{
  ArrayList tmp = new ArrayList();
  ...
  return tmp;
}

Dan zou .remove() sowieso geen nut hebben Tongue.

Dat gebeurt in dit geval wel. Het is een onderdeel van de Bukkit API waarmee ik gedropte items kan opvragen bij het dood gaan van een speler.

Maar een ArrayList is gewoon een mutable object waaraan hij dingen kan toevoegen, ergens in de code ervan uitgaan dat deze non-mutable is geeft een behoorlijke kans dat je later fouten introduceert. Lijkt me niet bepaald good practise, eerlijk gezegd.

In Java 8 hebben we tegenwoordig trouwens ook Collection.RemoveIf, superhandig! Smiley

https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-

Java 8 is helaas geen mogelijkheid. Zoals ik al zei gebruik ik de Bukkit API en de Minecraft server draait op Java 7.

Als je er met een Iterator overheen loopt kun je Iterator.remove() gebruiken. Smiley

Dit ga ik proberen.
Gelogd

@-wout
Administrator
Approaching infinity
*********

Berichten: 9.426



Bekijk profiel WWW
« Antwoord #6 Gepost op: 06 November 2015, 17:25:03 »

Iterator is hier voor gemaakt, raad dan ook aan om die te gebruiken Wink
Gelogd

Maarten
Approaching infinity
********

Berichten: 8.271



Bekijk profiel
« Antwoord #7 Gepost op: 07 November 2015, 21:10:13 »

Het werkt, thanks iedereen Smiley

Voor de mensen met een vergelijkbaar probleem:
Code:
ListIterator<ItemStack> itr = event.getDrops().listIterator();
while(itr.hasNext()){
    ItemStack drop = itr.next();
    if (...)
        itr.remove();
    }
}
Gelogd


Advertenties
Pagina's: [1]
  Print  

 
Ga naar:  

Powered by SMF 1.1.21 | SMF © 2006-2011, Simple Machines | Smartphoneversie bekijken

Dilber MC Theme by HarzeM