問題描述
考慮以下 Java 源代碼:
Consider the following Java source:
if( agents != null ) {
for( Iterator iter = agents.keySet().iterator(); iter.hasNext(); ) {
// Code that uses iter.next() ...
//
}
}
agents
是一個 HashMap
.
為什么 for
語句有時會拋出 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
}
}
}
如果另一個線程在 if
語句執行后立即將 agents
設置為 null
(但在 for
循環之前),然后你會得到一個 NullPointerException
.通過使用訪問器(結合惰性初始化)來避免這種情況.
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).
另外,正如其他人所提到的,如果可能,請避免使用泛型來支持此類循環構造.有關詳細信息,請參閱其他答案.
Also, as others have mentioned, avoid such looping constructs in favour of generics, if possible. See other answers for details.
訪問器提供保護
如果您始終使用以下模式,您的源代碼中將永遠不會出現 NullPointerException
(另一方面,第三方代碼可能存在導致您的代碼間接失敗的問題,這是無法輕易避免的).
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
(或任何其他抽象數據類型,例如 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
.
開閉原則
如果您覺得自己的時間特別慷慨,您可以這樣做:
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();
}
}
這將允許子類(由其他開發人員編寫)替換他們自己正在使用的抽象數據類型的子類(允許系統更大的靈活性以符合 開放-封閉原則),無需修改(或復制/浪費)您的原創作品.
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.
這篇關于為什么這段代碼有時會拋出 NullPointerException?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!