考虑以下Java源代码:
if( agents != null ) {
for( Iterator iter = agents.keySet().iterator(); iter.hasNext(); ) {
// Code that uses iter.next() ...
//
}
}
agents
是HashMap
。
为什么for
语句有时会抛出NullPointerException
?
谢谢。
答案 0 :(得分: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
}
}
}
如果另一个线程在agents
语句执行后(但在null
循环之前)立即将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
}
}
}
迭代代理的代码不再需要检查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();
}
}
这将允许子类(由其他开发人员编写)替换他们自己使用的抽象数据类型的子类(允许系统更灵活地与Open-Closed Principle保持一致),而无需修改(或复制/浪费你原来的工作。
答案 1 :(得分:5)
这不应该是一个while循环吗?
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
}
}
答案 2 :(得分:0)
确保没有在循环内将iter
设置为null。