简体   繁体   English

ArrayList仅在arraylist中的对象上的索引超出范围异常

[英]ArrayList Index out of bounds exception on only object in the arraylist

I know this has probably been asked many times before, but I have a problem and I could not find a solution that particularly targeted my issue. 我知道这个问题以前可能已经被问过很多遍了,但是我有一个问题,我找不到特别针对我的问题的解决方案。

The problem is as follows: 问题如下:

I have two arraylists of rockets and projectiles, and collision is checked between them. 我有两个火箭和弹丸的数组列表,并检查了它们之间的碰撞。 When they collide, both of them are removed. 当它们碰撞时,它们都将被移除。 The problem is that when the only rocket in the arraylist is hit, the exception occurs, and I have no idea how to stop it from happening. 问题是,当击中arraylist中唯一的火箭时,就会发生异常,而我不知道如何阻止它的发生。

java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at adam.miszczak.defendthebase.level.Level.collision(Level.java:158)
at adam.miszczak.defendthebase.level.Level.tick(Level.java:144)
at adam.miszczak.defendthebase.Game.tick(Game.java:124)
at adam.miszczak.defendthebase.Game.run(Game.java:104)
at java.lang.Thread.run(Unknown Source)

Collision method + the arraylists: 碰撞方法+数组列表:

public static ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
private static ArrayList<Rocket> rockets = new ArrayList<Rocket>();

private void collision(){
    for(int i = 0; i < rockets.size(); i++){
        for(int j = 0; j < projectiles.size(); j++){
            try{
                if(rockets.get(i).bounds().intersects(projectiles.get(j).bounds())){
                    projectiles.remove(j);
                    rockets.get(i).die();
                    stats.addScore(rockets.get(i));
                    Particle p = new Particle(20, 20, 20, 50);
                    particles.add(p);
                }
            }catch(IndexOutOfBoundsException e){
                e.printStackTrace();
            }
        }
    }
}

Remove and Add methods: 删除和添加方法:

private void remove(ArrayList<Projectile> projectiles, ArrayList<Rocket> rockets){
    for(int i = 0; i < rockets.size(); i++){
        if(rockets.get(i).getVisible()){ rockets.remove(i); rocketsOnScreen--; }
    }

    for(int i = 0; i < projectiles.size(); i++){
        if(projectiles.get(i).isRemoved()){ projectiles.remove(i);}
    }

    for(int i = 0; i < planes.size(); i++){
        if(planes.get(i).isRemoved()){ planes.remove(i); planesOnLevel--;}
    }
}

private void spawnRocket(int rocketType, int x, ArrayList<Rocket> rockets) {
    switch (rocketType) {
        case ROCKET_NORMAL:
            rockets.add(new NormalRocket(x, -10, 80, 0, 2));
            rocketsSpawned++;
            rocketsOnScreen++;
            break;
        case ROCKET_FIRE:
            if(difficulty > 1 && random.nextInt(100) > fireRocketSpawn){
                    rockets.add(new FireRocket(x, -10, 70, 0, 2));
                    rocketsSpawned++;
                    rocketsOnScreen++;
            }else{
                return;
            }
            break;
        case ROCKET_ZIPPER:
            if(difficulty > 2 && random.nextInt(100) > zipperRocketSpawn){
                rockets.add(new ZipperRocket(x, -10, 40, 0, 4));
                rocketsSpawned++;
                rocketsOnScreen++;
            }else{
                return;
            }
            break;
        case ROCKET_TANK:
            if(difficulty > 3 && random.nextInt(100) > tankRocketSpawn){
                rockets.add(new TankRocket(x, -10, 130, 0, 1));
                rocketsSpawned++;
                rocketsOnScreen++;
            }else{
                return;
            }
            break;
    }
} 

NOTE: rocket.die() basically just removes the rocket, the same way the remove method would do. 注意:rocket.die()基本上只是删除火箭,就像remove方法一样。

You cannot remove while iterating over a List with anything other than an Iterator . 使用Iterator以外的其他任何方法遍历List无法删除。 Imagine the consequences; 想象一下后果。 you are looping over the elements and remove element n . 您正在遍历元素并删除元素n All other elements shift down one to fill the gap. 所有其他元素向下移动一个以填补空白。 You take element n+1 , this is now element n+2 from when you started looping. 您取元素n+1 ,现在是开始循环时的元素n+2 And the List is one element smaller so your bounds check is now wrong. 而且List缩小了一个元素,因此您的边界检查现在是错误的。 You can get all sorts of hard to track-down bugs in this manner. 您可以通过这种方式获得各种难以跟踪的错误。

In Java if you use the proper syntax - ie enhanced foreach loops then your will get the correct error if you even try to addto/deletefrom the list while iterating - you will get a ConcurrentModificationException . 在Java中,如果使用正确的语法(即增强的foreach循环),则即使您在迭代时甚至尝试从列表中添加/删除列表,也将获得正确的错误-您将获得ConcurrentModificationException

To fix your method, 1) get rid of all the indices. 要修正您的方法,请执行以下操作:1)删除所有索引。 You are abusing them and they are unnecessary (now many times do you get the same element from each List in each iteration?) . 您正在滥用它们,它们是不必要的(现在很多时候,您在每次迭代中是否从每个List中获得相同的元素?)。 2) use an actual Iterator for the inner loop so that you can call Iterator.remove to remove the last returned element from the List . 2)对内部循环使用实际的Iterator ,以便可以调用Iterator.removeList删除最后一个返回的元素。 Because that is done via the Iterator it doesn't result in an error: 因为这是通过Iterator完成的,所以不会导致错误:

private void collision() {
    for (final Rocket rocket : rockets) {
        final Iterator<Projectile> iter = projectiles.iterator();
        while (iter.hasNext()) {
            final Projectile projectile = iter.next();
            if (rocket.bounds().intersects(projectile.bounds())) {
                rocket.die();
                stats.addScore(rocket);
                Particle p = new Particle(20, 20, 20, 50);
                particles.add(p);
                iter.remove();
            }
        }
    }
}

Never remove items of a list during a loop through the list. 切勿在列表循环中删除列表中的项目。 It might give concurrency oroblems. 它可能会带来并发障碍。 Mark the numbers for removal right after the loop. 在循环之后立即标记要删除的数字。

Not sure if it will fix your problem, but sure enough you should fix that too. 不知道它是否可以解决您的问题,但您肯定也应该解决该问题。

When the collision is detected you call 当检测到碰撞时,您致电

rockets.get(i).die();

'die' removes the rocket from the 'Arraylist', you say. 您说,“ die”将火箭从“ Arraylist”中移除。 Then you call 然后你打电话

stats.addScore(rockets.get(i));

which will crash (this line is 158, isn't it? ) 这将崩溃(此行是158,不是吗?)

Apologies for brevity and formatting, first answer from my phone :-) 为简洁和格式而道歉,我的手机首先回答了:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM