为什么这段代码有时会抛出NullPointerException?

问题描述

如果您的代码是多线程的,则有可能。例如:

public class C {
  private Hashtable agents = new Hashtable();

  public iterate() {
    if( agents != null ) {
      for (Iterator iter = agents.keySet().iterator(); iter.hasNext();) {
        // Code goes here
      }
    }
}

如果在语句执行之后(但在循环之前)立即将另一个线程设置agents为,则您将获得一个。通过使用访问器(与延迟初始化结合使用)可以避免这种情况。null``if``for``NullPointerException

另外,如其他人所提到的,如果可能,请避免使用有利于泛型的此类循环构造。有关详细信息,请参见其他答案。

如果始终使用以下模式,则NullPointerException代码中将永远不会包含s(另一方面,第三方代码可能会间接导致某些原因导致代码失败,这很难避免)。

public class C {
  private Hashtable agents;

  private synchronized Hashtable getAgents() {
    if( this.agents == null ) {
      this.agents = new Hashtable();
    }

    return this.agents;
  }

  public iterate() {
    Hashtable agents = getAgents();

    for (Iterator iter = agents.keySet().iterator(); iter.hasNext();) {
      // Code goes here
    }
  }
}

遍历代理的代码不再需要检查null。由于许多原因,此代码更加健壮。您可以用Hashmap(或其他任何抽象数据类型,例如ConcurrentHashMap<K,V>)代替Hashtable

如果您对自己的时间特别慷慨,则可以进行以下操作:

public class C {
  private Hashtable agents;

  private synchronized Hashtable getAgents() {
    if( this.agents == null ) {
      this.agents = createAgents();
    }

    return this.agents;
  }

  public iterate() {
    Iterator i = getAgentKeyIterator();

    while( i.hasNext() ) {
      // Code that uses i.next() ...
    }
  }

  protected Hashtable createAgents() {
    return new Hashtable();
  }

  private Iterator getAgentKeyIterator() {
    return getAgentKeys().iterator();
  }

  private KeySet getAgentKeys() {
    return getAgents().keySet();
  }
}

这将允许子类(由其他开发人员编写)替换他们自己的正在使用的抽象数据类型的子类(使系统在遵循开放式封闭原则的情况下具有更大的灵活性),而无需修改(或复制/浪费)原始的工作。

解决方法

考虑以下Java源代码:

if( agents != null ) {
  for( Iterator iter = agents.keySet().iterator(); iter.hasNext(); ) {
    // Code that uses iter.next() ...
    //
  }
}

agentsHashMap

为什么该for语句有时会抛出NullPointerException

谢谢。