2015-02-12 43 views
4

我使用的IntelliJ IDEA,以及後續的代碼生成一個警告:如果我標誌着testObj瞬態「Expression testObj might evaluate to null but is returned by the method declared as @NotNull (at line 16)Java的transient關鍵字和空

package com.dlp; 

import javax.annotation.Nonnull; 
import javax.annotation.Nullable; 

public class TestCase { 
    @Nullable 
    private transient Object testObj = null; 

    @Nonnull 
    public Object getTestObj() { 
     if(testObj == null) { 
      testObj = new Object(); 
     } 

     return testObj; //Line 16 
    } 
} 

這只是發生。刪除關鍵字將清除警告。我沒有獲得暫態和可空性之間的一些交互,或者這只是IDEA中的一個錯誤?

+0

唯一的事情就是顯而易見 - 如果一個可序列化的實例被反序列化,它將爲空,除非它被處理了。 – jdphenix 2015-02-12 04:26:26

+0

@ jdphenix但是該方法已經檢查了這種情況。雖然如果這個對象被反序列化,那麼testObj將是空的,但這同樣適用於默認初始化爲空的非瞬態字段。我已經將該字段標記爲@Nullable。該領域如何變爲空值不應該成爲一個問題。 什麼奇怪的是,IDEA認爲testObj可以爲空_immediately after_檢查它不是。 – RandomBK 2015-02-12 04:33:41

+0

確實 - 我懷疑是bug。 – jdphenix 2015-02-12 04:36:31

回答

0

編譯器中的可空性非常嚴格。是的,你檢查null,但是有一個問題,你的代碼可能在多線程環境中使用。考慮這種情況:在執行

塊:

if(testObj == null) { 
     testObj = new Object(); 
    } 

當前線程是捷足先登,而另一個線程走來,並設置testObj爲null。然後原始線程再次變爲活動並結束執行,並返回nulltestObj

寫這個代碼,以避免空警告正確的方法是這樣的:

public Object getTestObj() { 
    Object tmpObj = testObj 
    if(tmpObj == null) { 
     tmpObj = new Object(); 
     testObj = tmpObj; 
    } 

    return tmpObj; 
} 

在這種情況下,可以保證返回值永遠不能爲null。當然,這是一個非常嚴格的角落案例,大多數程序將永遠不需要這個級別的安全性,但編譯器應該如何檢查null。

當您添加瞬態時,null警告消失的事實看起來像是一個IntelliJ錯誤。但是,上面提出的代碼是處理字段空泛性的正確方法。如果這對你來說過於繁重,我建議避免在字段上添加空註釋。

+0

我想你誤解了我的問題。當我使用transient關鍵字時,_only_發生警告。我知道線程會混淆這個方法,而在多線程環境下做這樣的事情需要volatile關鍵字或某種同步/內存障礙(我不完全確定你的解決方案是否可以工作,由於內存緩存和java的內存模型)。這裏的奇怪之處在於,IDEA非常高興_without_ transient_關鍵字,但開始變得不安。 – RandomBK 2015-02-12 05:07:04

+0

在我最後一段中,我提到帶有* transient關鍵字的行爲*可能是正確的,沒有它的行爲很奇怪。 – 2015-02-12 05:23:13