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

请考虑以下Java源代码:

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

agentsHashMap

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

谢谢。

线程安全

如果您的代码是multithreading的,那么它是可能的。 例如:

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

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

此外,正如其他人所提到的,如果可能的话,避免使用这种循环结构来支持generics。 请参阅其他答案了解详情

存取器提供保护

如果您始终使用以下模式,则源代码中永远不会出现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 } } } 

迭代代理的代码不再需要检查null 。 由于许多原因,此代码更加强大。 您可以将Hashmap (或任何其他抽象数据类型,例如ConcurrentHashMap )替换为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(); } } 

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

这不应该是一个循环?

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

或每个?

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

确保在循环内没有将iter设置为null。