07. januar 2002 - 07:33Der er
54 kommentarer og 1 løsning
ArrayIndexOutOfBoundsException
Een af mine vectorer laver en ArrayIndexOutOfBoundsException... Hvordan pokker kommer jeg lige uden om den?
public void detectCollision() { for ( int i = 0; i < bullets.size(); i++) { for ( int k = 0; k < enemies.size(); k++) { Koordinater bullet = (Koordinater)bullets.get(i); xPosB = bullet.getX(); yPosB = bullet.getY();
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 45 at java.util.Vector.get(Vector.java:699) at CollisionDetector.detectCollision(CollisionDetector.java:44) at CollisionDetector.run(CollisionDetector.java:34) at java.lang.Thread.run(Thread.java:484)
Nu så den FX sådan nu: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 404 at java.util.Vector.get(Vector.java:699) at CollisionDetector.detectCollision(CollisionDetector.java:48) at CollisionDetector.run(CollisionDetector.java:34) at java.lang.Thread.run(Thread.java:484)
Jeg tror dit problem er at du fjerner en fjende, men så kører din fjende løkke videre uændret. Efter at have fjernet en fjende skal du bruge k--; så tror jeg det funker.
Sker der noget med bullets i en anden tråd, så antallet ændrer sig mens du checker?
Du skal også lige huske k-- som anført, så du ikke springer nogen over. Men det kan ikke gíve indexfejl at glemme.
Og så kan du gøre det lidt mere effektivt - og overskueligt:
public void detectCollision() { for ( int i = 0; i < bullets.size(); i++) { Koordinater bullet = (Koordinater)bullets.get(i); xPosB = bullet.getX(); yPosB = bullet.getY(); for ( int k = 0; k < enemies.size(); k++) {
public class CollisionDetector implements Runnable { public CollisionDetector(Vector bullets, Vector enemies) { this.bullets = bullets; this.enemies = enemies; }
public void start() { if (collisionDetector == null) { collisionDetector = new Thread(this); collisionDetector.start(); } }
public void run() { while (true) { try { collisionDetector.sleep(20); } catch(Exception e) { }
detectCollision(); } }
public synchronized void detectCollision() { for ( int i = 0; i < bullets.size(); i++) { for ( int k = 0; k < enemies.size(); k++) { Koordinater bullet = (Koordinater)bullets.get(i); xPosB = bullet.getX(); yPosB = bullet.getY();
private int xPosB; private int yPosB; private int xPosE; private int yPosE; private int starClass; private Vector bullets; private Vector enemies; private Thread collisionDetector; public int counter; }
Men, nu læser jeg hvad du skriver, din \"synchronized\" løser jo ikke dit problem, hvis der sker ændringer i dine Vector-er andet sted, mens du checker.
Ja, det gør der vel egentlig... Tag en kigger på www.be-reminded.dk/myshooter Der kan i se hele appletten. Jeg tager jo egentlig nogle kugler og enemies ud når de rammer siden.. Det skulle jeg bare putter i den samme metode og lukker eller noget... Så kan det være den er der
Hvis man går ud fra at en bullet kun kan ramme én enemy, så skulle et break statement kunne løse dit problem, samtidig med at din kode bliver en anelse hurtigere.
Her er din yderste løkke labelled slut. Derfor afbryder break slut den yderste og dermed også den inderste løkke; Hvis du fjerner slut, vil den yderste løøke køre ti gange, som den skal, mens den inderste aldrig når mere end en tur.
public class BreakTest {
public static void main( String[] argv ){ slut: for ( int i = 0 ; i < 10 ; i++ ) { for ( int j = 0 ; j < 10 ; j++ ){ System.out.println( \"\"+ i +\", \" + j ); break slut; } } } }
Jeg laver mig sgu bare en ny collision klasse eller noget. Og så laver jeg 2 arrays istedet hvor der kun kan være så og så mange elementer i. Så kan det da være jeg slipper for den lorte arrayIndexOutOfBoundsErrorException..
Du misser noget her. Der er ikke spor af goto i det eksempel. Der er nogle nestede loops, hvoraf det yderste er navngivet. Når break kaldes med en label, fortæller man bare hvilken kontrolstruktur, der skal udføres break på. Hvis det havde været noget der lignede goto, ville løkken jo bare have startet forfra.
Hvis jeg må tillade mig at støtte disky, vil jeg da lige forklare hvorfor jeg også mener goto, break, og returns, der ikke står til sidst i en metode generelt set er dumme. Man skal nemlig kunne formulere invarianter flere steder i sine metoder, dvs. \"små\" logiske udtryk, der fortæller hvad der gælder på et givet sted i metoden. Det er ikke altid man gider formulere dem direkte, men har man ikke programmeret med dem i tankerne får man den spaghettikode, der ofte ses i de kodestumper, der vælter ud af spørgsmålene på eksperten.dk.
Skal man så bruge goto-lignende tingester må de ikke overskride de steder man har sine invarianter, for så ryger logikken i metoden, og dermed bliver den sikkert forkert.
Eksempel:
public int sum(int a, int b) { // Prebetingelse a>0 og b>0 int a1=a; int b1=b; while (a1<>0) { // Invariant: a+b=a1+b1 a1--; b1++; } // Invariant: a1=0 og a+b=a1+b1, dvs. a+b=b1 // Postbetingelse: b1=a+b return b1; }
Ja, et dumt lille eksempel, men bare for at illustrere. Jeg har \"bevist\" at ved at lægge én til og trække én fra tilstrækkeligt mange gange, kan man addere tal.
Uenigheden fra min side går mere på firkantede holdninger. Fordi der kan findes (mange) eksempler på at en given fremgangsmåde kan give probelmer eller uoverskuelighed, er det ikke nødvendigvis det samme som at den fremgangmåde ikke kan være velegnet i andre tilfælde. Hvad jeg mener er at fordi det gentagne gange har vist sig at give problemer at transportere mursten i en bus, er det vel ikke ensbetydende med at man skal lade være med at bruge den til passagerer.
Efter følgende gøres det samme to gange. 1. gang som disky foreslår, ved at checke en boolean. 2. gang med break label. Begge dele giver præcis samme resultat og samme programflow, men der er et fuldstændig unødvendigt overhead ved at checke en boolsk værdi i samme gennemløb.
Hvis man så påstår at den metode, der gør arbejdet på den mest besværlige måde, er den bedste, fordi det andet \"gør man bare ikke\", så er og bliver det et religionsspørgsmål, og ikke andet. Samtidig er I jo fortalere for at man bruger Javas indbyggede metoder, fordi de pr. definition er de bedste. Break to label er også en del af Java. Det hænger ikke rigtig sammen.
public class BreakTest {
public static void main( String[] argv ){ boolean fundet = false; for ( int i = 0 ; i < 10 && !fundet ; i++ ) { for ( int j = 0 ; j < 10 && !fundet ; j++ ){ System.out.println( \"\"+ i +\", \" + j ); if (i == 2 && j == 5){ fundet = true; } } } slut: for ( int i = 0 ; i < 10 ; i++ ) { for ( int j = 0 ; j < 10 ; j++ ){ System.out.println( \"\"+ i +\", \" + j ); if (i == 2 && j == 5){ break slut; } } } } }
Som et kuriosum kan nævnes at i C#, som Anders Hejlsberg er primus motor bag, har man genindført goto:-))
Du har argumenteret for at bruge en label. pludselig retter du din betingelse til at indeholde en if for at kunne tegne et diagram (det med det mystiske navn) så bruger du jo heller ikke en label længere, men den metode jeg foreslog.
Du bliver ved med at hænge dig i labels. Og du bliver ved med at omtale dem som om det var noget i forbindelse med goto. Prøv at sætte en label et tilfældigt sted i koden, og se om du kan få programflowet til at fortsætte der ved hjælp af break. Det giver en compileringfejl. Det eneste du kan med break og label at at afbryde udførelsen af en nestet kontrolstruktur - igen - fuldstændigt equivalent med at checke på en boolean, men uden det ekstra arbejde.
forslag til løsning - lav endnu en vector (\"removalvector\") til at holde de fjender som skal fjernes/dø. Istedet for at fjerne dem inde i dit collision-check, så tilføj dem til din removalvector. Efter dit collisions-check fjerner du så de elementer i removalvectoren fra enemies-vectoren
Inden vi stopper helt, så lad mig lige præcisere at jeg godt synes man kan bruge break, continue \"i det små\", altså mellem mine mere eller mindre eksplicitte invarianter. Er der en for-løkke på ganske få linier, hvor for og break står \"tilstrækkelig tæt\" på hinanden, og det ligner en velkendt konstruktion, så man isoleret set kan se hvad der sker, så ok med mig. Break til en navngiven label, fordi man skal ud af en løkke et trin længere ude er nok over grænsen til hvad jeg vil synes om.
Og så er jeg iøvrigt hamrende ligeglad med effektivitet. Programkoden skal både være korrekt, og kunne ses at være korrekt. Det andet princip kender vi alt for godt: blå skærm.
Jah, disky, i dette tilfælde gør det ikke nogen forskel efter whileløkken, for det eneste man ved gælder der er !iter.hasNext(). Skulle man standse på count, bør den være med i betingelsen, så man nemt kan se hvad der gælder efter løkken. Igen: det er ikke altid man skriver det, men man bør tænke det. Generelt:
while (BETINGELSE) { alt muligt uden break; } // Nu gælder med garanti: !BETINGELSE
(Undskyld bootie: det er både charmen OG ulempen ved eksperten.dk, når et spørgsmål går ud af en tangent. Du burde måske - hvis du har mere at spørge om - lave et friskt spørgsmål)
erik: Det gør da ikke noget. Jeg er selv født up med at break og continue og labels ikke er så smarte at bruge umiddelbart. Så jeg er bare med på en lytter :) Man er jo aldrig for gammel til at lære nye trix
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.