简体   繁体   English

ArrayList.remove(Object)抛出ArrayIndexOutOfBoundsException:-1

[英]ArrayList.remove(Object) throws an ArrayIndexOutOfBoundsException: -1

I have an observable, that notifies all of its registered observers. 我有一个观察员,它通知其所有注册观察员。

public void notifyObservers(T message) {
      notifying = true;
      for (Observer<T> observer : observers)
         observer.notify(message);
      notifying= false;
   }

I also have this method in my observable class: 我的可观察类中也有此方法:

public void removeObserver(final Observer<T> observer){
  if (!this.observers.contains(observer))
     return;

  if (!notifying) {
     this.observers.remove(observer);
     return;
  }

  final ArrayList<Observer<T>> observerList = this.observers;
  new Thread(new Runnable() {

     public void run() {
        while (notifying);
        observerList.remove(observer);
     }
  }).start();

}

To make shure that the remove calls are not made during the notifying, i wait in an new Thread for the notifying to be finished. 为了确保在通知期间不进行remove调用,我在新线程中等待通知完成。 However, one of the added Observers is calling the removeObserver -method of the observable it is added to in its notify -method and I get an ArrayIndexOutOfBoundsException in the line of the removecall of the ArrayList: 但是,添加的Observers之一在其notify -method中调用了将其添加到的可观察对象的removeObserver方法,并且在ArrayList的removecall行中得到了ArrayIndexOutOfBoundsException:

Exception in thread "Thread-4" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.fastRemove(Unknown Source)
    at java.util.ArrayList.remove(Unknown Source)
    at allgemeines.Observable$2.run(Observable.java:96)
    at java.lang.Thread.run(Unknown Source)

Why could that happen? 为什么会发生这种情况?

Instead of using the notifying boolean, why not use locking with synchronized? 为什么不使用带有同步的锁定,而不是使用通知布尔值? Something like: 就像是:

public void notifyObservers(T message) {
  synchronized(observers) {
    for (Observer<T> observer : observers)
       observer.notify(message);
  }

... ...

public void removeObserver(final Observer<T> observer){
   synchronized(this.observers) { 

     final ArrayList<Observer<T>> observerList = this.observers;

     observerList.remove(observer);
   }
}

Your code isn't thread safe. 您的代码不是线程安全的。 try to lock your observers by synchronized in the remove and notify methods. 尝试通过同步remove和notify方法来锁定您的观察者。

Solved it! 解决了! Well, I could'nt figure out why the Exception was thrown in my example in the question above, but I found a way to rewrite the method that worked. 好吧,我无法弄清楚为什么在上面的问题中的示例中抛出了Exception,但是我找到了一种重写有效方法的方法。 I converted the list into an array and iterated over that array instead of the list, which is an attribute: 我将列表转换为数组,然后遍历该数组而不是列表,列表是一个属性:

@SuppressWarnings("unchecked")
public synchronized void notifyObservers(T message) {
    Object[] observerArray = observers.toArray();
    for (Object observer : observerArray)
        ((Observer<T>) observer).notify(message);
}

The add and remove methods are now very simple (just delegating the method call to the ArrayList -methods: 现在, addremove方法非常简单(只需将方法调用委托给ArrayList方法即可:

public void addObserver(Observer<T> observer){
    this.observers.add(observer);
}

public void removeObserver(Observer<T> observer) {
    this.observers.remove(observer);
}

Would be still interesting to know why my first solution didn't work. 知道为什么我的第一个解决方案不起作用仍然会很有趣。

It is also possible to remove from the bottom up, that way you shouldn't be out of bounds. 也可以从下至上删除,这样就不会超出范围。 Don't know if this will help with your particular problem though. 不知道这是否可以解决您的特定问题。

for (int i = list.Count-1; i>-1; i--)
{
    list.RemoveAt(i);
}

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

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