为什么这段代码有时会抛出NullPointerException?
请考虑以下Java源代码:
if( agents != null ) { for( Iterator iter = agents.keySet().iterator(); iter.hasNext(); ) { // Code that uses iter.next() ... // } }
agents
是HashMap
。
为什么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。