2016-08-04 53 views
3

我以下代碼:爲什麼在這裏NetBeans顯示關於空指針解除引用的警告?

import java.util.concurrent.ConcurrentHashMap; 
import java.util.concurrent.ConcurrentMap; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class NullDereference { 

    private static final ConcurrentMap<Integer, Object> MAP = new ConcurrentHashMap<>(); 

    public static void main(String[] args) { 
     Object object = getObject(1); 

     if (object == null) { 
      Lock lock = new ReentrantLock(); 
      lock.lock(); 
      try { 
       lock.newCondition().await(1, TimeUnit.SECONDS); 

       object = new Object(); 
       object = addObject(object); // [3] 
      } catch (InterruptedException ex) { 
       throw new RuntimeException(ex); 
      } finally {  // [1] 
       lock.unlock(); // [1] 
      } 
     } 

     System.out.println("class: " + object.getClass()); // [2] 
    } 

    private static Object getObject(int hashCode) { 
     return MAP.get(hashCode); 
    } 

    private static Object addObject(Object newObject) { 
     Object oldObject = MAP.putIfAbsent(newObject.hashCode(), newObject); 
     if (oldObject != null) { 
      return oldObject; 
     } 

     return newObject; 
    } 
} 

NetBeans的顯示警告有關在線路 「取消引用可能空指針」[2]。我不知道爲什麼。我認爲這是因爲行[3],但是當我註釋掉行[3]時,警告仍然存在。當我在行[2]之前顯式檢查空值時,或者當我註釋掉整個finally語句(由[1]註釋的行)時,該警告消失。

我分析了代碼,認爲這一個是誤報。我對麼?

我不想額外檢查空指針。這段代碼有什麼問題?我可以改變一些東西來使代碼沒有警告嗎?

+0

因爲沒有強大的聲明,認爲編譯器,「對象」被初始化,永遠不會給null –

回答

1

我可以重現這一點。簡而言之:你是對的,它看起來像NetBeans的bug。 Eclipse和IDEA在此處不顯示警告。因爲它需要仔細遍歷所有可能的控制流路徑(我實際上正在編寫類似的分析器,所以我知道它很難),所以發佈「可能的空解除引用」警告並不是非常簡單的靜態分析。由於finally使事情變得更加困難,因爲finally節在每個代碼路徑後執行,然後將控制權返回給原始代碼。正確的控制流程圖必須重複最後一個塊的重複,添加多個輸入和輸出邊是不夠的。我可以推測,NetBeans不正確地完成這部分。

這裏是不正確的控制流圖草圖:

[ try { lock.newCondition().await(...) ...} ] 
     /  |   \ 
     /   |   \ 
    /   |   \ 
Successful InterruptedException other exception 
Execution   |    /
    \    |   /
     \    |   /
     \   |   /
    [ finally { lock.unlock; } ] 
    /   |   \ 
    /   |    \ 
    /   |    \ 
    |    |    | 
[System.out] [throw RuntimeEx] [throw the original exception] 

請參閱沿着這條曲線下降邊緣可以InterruptedException或其他一些異常後參觀最終System.out聲明。正確的圖形必須finally塊的三個副本:

[ try { lock.newCondition().await(...) ...} ] 
     /  |   \ 
     /   |   \ 
    /   |   \ 
Successful InterruptedException other exception 
Execution   |    | 
    |    |    | 
[finally_copy1] [finally_copy2] [finally_copy3] 
    |    |    | 
    |    |    | 
[System.out] [throw RuntimeEx] [throw the original exception] 

這樣,你只能成功try執行後到達System.out語句時object是肯定分配。

相關問題