2014-03-30 43 views
5

如果我將這段代碼的else部分更改爲else語句,它運行時沒有任何問題,所以我得到如何使其運行。我有點困惑的是爲什麼當它處於當前形式時我得到了一個丟失的return語句錯誤。我的返回取決於負值的布爾變量的值。我涵蓋了真實和虛假的狀態,是不是足夠覆蓋一切?爲什麼這段代碼有一個缺失的return語句錯誤?

或者是我總是必須在else中有return語句,或者爲我的函數的底部添加一個無意義的返回值,以便編譯器接受我的代碼作爲覆蓋每種情況?

import java.util.*; 
import java.lang.*; 
import java.io.*; 

class Ideone 
{ 
    public boolean posNeg(int a, int b, boolean negative) { 
     if (!negative) { 
     return (a < 0 && b > 0) || (a > 0 && b < 0); 
     } 
     else if (negative) { 
     return (a < 0 && b < 0); 
     } 
    } 

    public static void main (String[] args) throws java.lang.Exception 
    { 
    } 
} 
+1

如果'!negative'爲'false',不是'negative''true'?你爲什麼要這樣寫?我想你可以抱怨編譯器應該能夠爲你弄清楚,但它顯然不能。爲什麼呢?你知道編譯器試圖弄清楚你的怪異代碼是否真的可以寫成if-else是多麼複雜嗎? – Jared

+0

你不需要'if':'return(negative &&(a <0 && b <0))|| (!negative &&((a < 0 && b > 0)||(a> 0 && b <0)));' – dasblinkenlight

+1

@Jared - 的確如此。編譯器不能總是確認所有的可能性都已經被考慮過了,但是如果你使用else塊或者在if/elses之後有返回值,它可以很容易地確定它。請記住,if語句中的布爾表達式並不總是像你的例子那樣簡單直接。 – jahroy

回答

5

當編譯器看到else if沒有else或尾隨return語句,它不能肯定所有的控制路徑將導致有效return語句。

編譯器有時可能很聰明,但在這種情況下它不會很聰明(也不應該)。

此行爲在您的示例中很有幫助:在此情況下,絕對沒有理由使用else if。簡單的else更容易閱讀,更簡潔,更不容易出錯。

else在這種情況下非常有表現力。這意味着「與if子句相反」,如果將來代碼發生變化,情況仍然如此。

如果編譯器允許,您當前的代碼將更可能包含和/或引入錯誤。

這是我怎麼會重寫方法體:

if (negative) { 
    return (a < 0 && b < 0); 
} 
else { 
    return (a < 0 && b > 0) || (a > 0 && b < 0); 
} 

一般來說,你應該更喜歡if (negative)if (!negative)除非有令人信服的理由(即可讀性)不這樣做。

此外,很多人(包括我自己)都試圖在if/else聲明中首先插入最簡單的子句。讓你的代碼容易閱讀是件好事。

查看StephenC的技術解釋和更多關於爲什麼編譯器以這種方式運行的背景的回答。

+0

編譯器不允許在這方面很聰明。看我的答案。 –

+0

@StephenC - 也許我選擇我的話很差。我的意思是編譯器經常做出_smart_決定,但在這種情況下它不會很聰明。正如您指出的那樣,它需要遵循特定的規則,以確保執行有效的return語句。 – jahroy

3

if =>else if =>其中是else條件?

對於退貨聲明,必須處理所有分支機構(條件)。

你可以這樣做:

if (!negative) 
    return (a < 0 && b > 0) || (a > 0 && b < 0); 
return (a < 0 && b < 0); 

或:

if (!negative) 
    return (a < 0 && b > 0) || (a > 0 && b < 0) 
else 
    return (a < 0 && b < 0); 

或(我的首選方式):

return negative ? (a < 0 && b < 0) : (a < 0 && b > 0 || a > 0 && b < 0) 

不過,我建議你避免消極條件在複雜的情況下,人類的大腦更難。即使是像IntelliJ這樣的一些Java IDE,也可以幫助找到這些模式來修復它們。
你會結束:

if (negative) 
     return (a < 0 && b < 0); 
else 
     return (a < 0 && b > 0) || (a > 0 && b < 0); 
+0

男孩是那些難以閱讀的建議......我只是用'if/else'保持簡單。 – jahroy

+0

這只是一個味道的問題 – Mik378

+0

你是絕對正確的。 – jahroy

2

你不需要「如果(負){}」中的「其他」梅開二度

+0

不僅沒有必要,而且增加了大量引入錯誤的可能性。 – jahroy

3

我想你已經知道,第二個如果是多餘的。

if (negative)被解釋爲無上下文,這意味着編譯器忽略已經處理了if(!negative)

4

其他問題已經從直觀的角度解釋了錯誤信息的含義。但是「編譯器很聰明,但不完美!」評論缺少重點。

事實上,Java編譯器正在調用您的示例的錯誤,因爲Java語言規範要求它稱它爲錯誤。 Java編譯器不允許對此「明智」


這裏是什麼JLS(用於Java 7 )實際上說的,以及它如何適用於不正確的示例的簡化版本,然後修正版本。

「如果一個方法被聲明爲有返回類型,然後如果該方法的主體可以正常完成(JLS 14.1)發生編譯時間錯誤。換句話說,與返回類型的方法必須只有通過使用return語句,提供了一個價值迴歸返回;它不允許「落其身上的終結」「 - JLS 8.4.7

(閱讀JLS 14.1用於定義‘正常完成’。 ..)

而規則用於判斷「正常」完成是否可能的是JLS 14.21中的可達性規則。他們說:

  1. 「的if-then語句可以正常完成當且僅當它是可到達。」
  2. 「如果then語句可以正常完成或者else語句可以正常完成,則if-then-else語句可以正常完成。」
  3. 「中斷,繼續,返回或拋出語句無法正常完成。」

(其中 '當且僅當' 的意思是 「當且僅當」 ......)

考慮實例的簡化版本:

public int test(boolean a) { 
     if (a) { 
     return 1; 
     } 
     else if (!a) { 
     return 0; 
     } 
    } 

在這個例子中,否則-statement是一個if-then,然後可以通過規則#1正常完成。因此,通過規則#2,if-then-else語句也可以正常完成。但是這是一個編譯錯誤,因爲JLS 8.4.7表示返回類型爲的方法不能正常完成

但是,如果你改變的例子來此...

public int test(boolean a) { 
     if (a) { 
     return 1; 
     } 
     else { 
     return 0; 
     } 
    } 

現在,通過規則#3,無論是if語句和其他語句無法正常完成。因此,通過規則#2,整個if-then-else無法正常完成。這就是它要求的JLS 8.4.7 ...因此沒有編譯錯誤。

1 - Java的8 JLS將從根本上說同樣的話,雖然部分數字可能會有所不同...

+0

感謝您的回答,但不明白您解釋示例的方式。你是說第一個例子是有效的,第二個例子不是?這就是我閱讀它的方式,對我來說沒有意義... – jahroy

+0

不,我是說第一個例子不是有效的Java,第二個例子是。要求是返回類型*的方法的方法體不能正常完成。如果可以的話,那就是編譯錯誤。 (更新回答澄清...) –

+0

好的。這就是我的想法,但我很難用你的話來找到這個意思。我認爲將「_completingnormal_」定義爲「_completing沒有帶有有效返回類型的顯式返回語句」會很有幫助。像往常一樣,規範中的語言並不直觀(在我看來)。 – jahroy

1

你應該在你所有的分支的回報。

public boolean posNeg(int a, int b, boolean negative) { 
    if (!negative) { 
    return (a < 0 && b > 0) || (a > 0 && b < 0); 
    } 
    else if (negative) { 
    return (a < 0 && b < 0); 
    } 
} 

上面的方法邏輯上在所有分支中都有返回,但從技術上講沒有。我們喜歡Java編譯器快速,因此不希望Java編譯器在語義上分析代碼。

public boolean posNeg(int a, int b, boolean negative) { 
    if (!negative) { 
    return (a < 0 && b > 0) || (a > 0 && b < 0); 
    } 
    else { 
    return (a < 0 && b < 0); 
    } 
} 

上述方法在所有分支中都有返回。

public boolean posNeg(int a, int b, boolean negative) { 
    if (!negative) { 
    return (a < 0 && b > 0) || (a > 0 && b < 0); 
    } 
    return (a < 0 && b < 0); 
} 

然而,正如你可以在上面看到,你甚至不需要別人的,因爲如果代碼沒有到達第二回,然後負肯定是假的,因爲如果這是真的,第一回將結束該算法。

public boolean posNeg(int a, int b, boolean negative) { 
    return ((negative) && (a < 0 && b < 0)) || ((!negative) && (a < 0 && b > 0) || (a > 0 && b < 0)); 
} 

上面的方法是單線程的。

public boolean posNeg(int a, int b, boolean negative) { 
    return ((negative) && (a < 0 && b < 0)) || ((!negative) && ((a < 0) == (b > 0))); 
} 

上述的方法使用的事實,在第二種情況下的a的陽性是具有b消極相等。