問題描述
考慮以下 Java 源代碼:
Consider the following Java source:
if( agents != null ) {
for( Iterator iter = agents.keySet().iterator(); iter.hasNext(); ) {
// Code that uses iter.next() ...
//
}
}
agents
是一個(gè) HashMap
.
為什么 for
語句有時(shí)會(huì)拋出 NullPointerException
?
Why does the for
statement sometimes throw a NullPointerException
?
謝謝.
推薦答案
線程安全
如果您的代碼是多線程的,那么這是可能的.例如:
If your code is multi-threaded, then it is possible. For example:
public class C {
private Hashtable agents = new Hashtable();
public iterate() {
if( agents != null ) {
for (Iterator iter = agents.keySet().iterator(); iter.hasNext();) {
// Code goes here
}
}
}
如果另一個(gè)線程在 if
語句執(zhí)行后立即將 agents
設(shè)置為 null
(但在 for
循環(huán)之前),然后你會(huì)得到一個(gè) NullPointerException
.通過使用訪問器(結(jié)合惰性初始化)來避免這種情況.
If another thread sets agents
to null
immediately after the if
statement executes (but before the for
loop), then you will get a NullPointerException
. Avoid this by using accessors (combined with lazy initialization).
另外,正如其他人所提到的,如果可能,請(qǐng)避免使用泛型來支持此類循環(huán)構(gòu)造.有關(guān)詳細(xì)信息,請(qǐng)參閱其他答案.
Also, as others have mentioned, avoid such looping constructs in favour of generics, if possible. See other answers for details.
訪問器提供保護(hù)
如果您始終使用以下模式,您的源代碼中將永遠(yuǎn)不會(huì)出現(xiàn) NullPointerException
(另一方面,第三方代碼可能存在導(dǎo)致您的代碼間接失敗的問題,這是無法輕易避免的).
If you always use the following pattern you will never have NullPointerException
s in your source code (third-party code, on the other hand, might have issues that cause your code to fail, indirectly, which cannot be easily avoided).
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
(或任何其他抽象數(shù)據(jù)類型,例如 ConcurrentHashMap<K,V>
)替換 Hashtable
.
The code that iterates over the agents no longer needs to check for null
. This code is much more robost for many reasons. You can substitute Hashmap
(or any other abstract data type, such as ConcurrentHashMap<K,V>
) for Hashtable
.
開閉原則
如果您覺得自己的時(shí)間特別慷慨,您可以這樣做:
If you were feeling especially generous with your time you could go as far as:
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();
}
}
這將允許子類(由其他開發(fā)人員編寫)替換他們自己正在使用的抽象數(shù)據(jù)類型的子類(允許系統(tǒng)更大的靈活性以符合 開放-封閉原則),無需修改(或復(fù)制/浪費(fèi))您的原創(chuàng)作品.
This would allow subclasses (written by other developers) to substitute their own subclass of the abstract data type being used (allowing the system greater flexibility in keeping with the Open-Closed Principle), without having to modify (or copy/waste) your original work.
這篇關(guān)于為什么這段代碼有時(shí)會(huì)拋出 NullPointerException?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!