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

Tib*_*riu 4 java hashmap

请考虑以下Java源代码:

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

agents是一个HashMap.

为什么for声明有时会抛出NullPointerException

谢谢.

Dav*_*vis 7

线程安全

如果您的代码是多线程的,那么它是可能的.例如:

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

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

如果另一个线程设置agentsnull立即后if语句执行(但在此之前的for循环),那么你会得到一个NullPointerException.通过使用访问器(结合延迟初始化)避免这种情况.

此外,正如其他人所提到的,如果可能的话,避免这种循环结构有利于泛型.请参阅其他答案了解详情

配件提供保护

如果您总是使用以下模式,那么NullPointerException您的源代码将永远不会出现(另一方面,第三方代码可能存在导致代码失败的问题,间接失败,这是不容易避免的).

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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

迭代代理的代码不再需要检查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();
  }
}
Run Code Online (Sandbox Code Playgroud)

这将允许子类(由其他开发人员编写)替换他们自己使用的抽象数据类型的子类(允许系统更灵活地保持开放 - 封闭原则),而不必修改(或复制/浪费)您的原始工作.


Pow*_*ord 5

这不应该是一个循环?

if (agents != null) {
    Iterator iter = agents.keyset().iterator();
    while (iter.hasNext()) {
        //some stuffs here
    }
}
Run Code Online (Sandbox Code Playgroud)

或每个?

if (agents != null) {
    //Assuming the key is a String
    for (String key : agents.keyset()) {
        //some stuffs here
    }
}
Run Code Online (Sandbox Code Playgroud)