2011-02-16 49 views
25

通常,switch語句中不需要缺省值。但是,在以下情況下,僅在取消註釋默認語句時才能成功編譯代碼。有人可以解釋爲什麼嗎?爲什麼在此代碼中的枚舉開關需要默認值?

public enum XYZ {A,B}; 
public static String testSwitch(XYZ xyz) 
{ 
    switch(xyz) 
    { 
    case A: 
     return "A"; 
    case B: 
    //default: 
     return "B"; 
    } 
} 

回答

34

,你必須取消對default是你的函數說,它返回一個String,但如果你只有AB定義case標籤,然後如果你在別的傳遞函數不會返回的值的原因。 Java要求所有聲明它們返回一個值的函數實際上會在所有可能的控制路徑上返回一個值,在你的情況下,編譯器不會確信所有可能的輸入都返回了一個值。

我相信(並且我不確定這一點),原因是即使您覆蓋了所有的enum個案,代碼在某些情況下仍可能會失敗。特別是,假設你編譯了包含這個switch語句的Java代碼(它工作的很好),然後在更改enum以便現在有第三個常量 - 比如說C - 但是你不用switch重新編譯代碼在它的聲明。現在,如果您嘗試編寫使用先前編譯的類的Java代碼並將C傳入此語句中,那麼代碼將不會返回值,從而違反所有函數始終返回值的Java合約。

從技術上講,我認爲真正的原因是JVM字節碼校驗器總是拒絕有一些控制路徑落在函數末尾的函數(見§ 4.9.2 of the JVM spec),所以如果代碼是編譯它,只會在運行時被JVM拒絕。因此,編譯器會給出錯誤報告存在問題。

0

因爲編譯器無法猜測,只有兩個在enum值,並迫使你從方法的返回值。 (然而我不知道爲什麼它不能猜測,也許它有反射的東西)。

+1

還有`null`。 – rlibby 2011-02-16 06:36:30

+0

是的,我不是爲什麼編譯器無法弄清楚XYZ只有2個元素。由於它將XYZ識別爲一種類型,因此它顯然已經進入代碼的一部分,並且應該能夠註冊僅存在兩個可能元素的事實。 – 2011-02-16 06:36:59

+0

@rlibby:我記得測試null是爲了看看它是否有所作爲,我認爲它沒有。但我會再檢查一次。 – apoorv020 2011-02-16 06:37:31

8

如前所述,您需要返回一個值,並且編譯器不會假定枚舉在將來不能更改。例如。您可以創建另一個枚舉版本並使用該版本,而無需重新編譯該方法。

注意:xyz的第三個值爲空。

public static String testSwitch(XYZ xyz) { 
    if(xyz == null) return "null"; 
    switch(xyz){ 
    case A: 
     return "A"; 
    case B: 
     return "B"; 
    } 
    return xyz.getName(); 
} 

此HA相同的結果

public static String testSwitch(XYZ xyz) { 
    return "" + xyz; 
} 

避免返回的唯一方式是拋出異常。

public static String testSwitch(XYZ xyz) { 
    switch(xyz){ 
    case A: 
     return "A"; 
    case B: 
     return "B"; 
    } 
    throw new AssertionError("Unknown XYZ "+xyz); 
} 
1

有一個合同,除非它拋出一個異常此方法返回一個字符串。並且每次不限於其中值xyz等於XVZ.AXYZ.B的那些情況。

這裏是另外一個例子,它是obviuos,該代碼將運行正確的,但我們有同樣的原因,一個編譯時錯誤:

public boolean getTrue() { 
    if (1 == 1) return true; 
} 

這是不是真的,你必須添加一個默認語句,這是真的,你必須隨時返回一個值。所以要麼添加一個默認語句,要麼在switch塊之後添加一個return語句。

32

我認爲這是由JLS明確賦值規則switch語句(JLS 16.2.9),其中列明瞭以下解釋:

V的(聯合國)分配一個switch語句後,」當且僅當以下所有條件都真:

  • 要麼有在開關塊中的默認標籤,或V是[未]開關表達之後分配

如果我們再應用此於想像V這是該方法的返回值,我們可以看到,如果沒有default分支,該值將是名義上未分配。

好的......我推斷明確的分配規則來覆蓋返回值,也許他們不會。但事實上,我無法找到的東西在規格更直接,並不意味着它不存在:-)


還有另一個(更多音)之所以編譯器必須給出一個錯誤。它從二進制兼容性規則enumJLS 13.4.26)莖,其說明如下:

「從枚舉類型添加或重新排序常量不會中斷與預先存在的二進制兼容性」。

那麼在這種情況下如何適用?那麼假設編譯器可以推斷出OP的示例switch語句總是返回一些東西。如果程序員現在更改enum以添加額外的常量,會發生什麼情況?根據JLS二進制兼容性規則,我們沒有破壞二進制兼容性。然而,包含switch語句的方法現在可以(取決於它的參數)返回一個未定義的值。 不能被允許發生,所以開關必須是一個編譯錯誤。