2009-12-24 56 views
25

考慮下面的代碼示例:Java是否識別無限循環?

public class WeirdStuff { 

    public static int doSomething() { 
     while(true); 
    } 

    public static void main(String[] args) { 
     doSomething(); 
    } 
} 

這是一個有效的Java程序,儘管該方法DoSomething的()應該返回一個int,但從來不會。如果你運行它,它會以無限循環結束。如果你把while循環的參數放在一個單獨的變量中(例如boolean bool = true),編譯器會告訴你在這個方法中返回一個int。

所以我的問題是:這是在Java規範的某個地方,是否有這種行爲可能有用的情況?

+0

難道你需要一個'返回0;'(或同等學歷)後',而(真);',只是爲了使編譯器幸福嗎?我知道我有Java抱怨方法不會返回正確的類型。這就是說,我完全可以看到這是一個編譯程序。 – 2009-12-24 14:49:55

+0

非常有趣...我很驚訝它實際編譯。 – cjstehno 2009-12-24 14:52:12

回答

19

我只是引用Java Language Specification,因爲它是對這個相當清楚的:

這部分是專門用於單詞的精確的解釋「可達」。這個想法是,從構造函數,方法,實例初始化程序或包含語句的靜態初始化程序的開頭,到語句本身必須有一些可能的執行路徑。分析考慮到了陳述的結構。除了特殊處理while,do和for語句的條件表達式的常量值爲真以外,表達式的值在流分析中未被考慮。

...

while語句可以完成正常且僅當以下至少有一個爲真:

  • while語句是可到達的條件表達式不是一個常數表達與真值。
  • 有一個可到達的break語句退出while語句。

...

在非空塊每隔的statement不是一個開關塊是當且僅當到達前S中的語句可以正常完成。

,然後應用上面的定義,以this

如果一個方法被聲明爲返回類型,然後在其身體的每一個return語句(§14.17)必須有一個表達。如果方法的正文可以正常完成(§14.1),則會發生編譯時錯誤。

換句話說,具有返回類型的方法必須通過使用一個返回語句,提供了一個值返回只返回;它不允許「落下其身體的末端」。

注意,這是可能的方法有一個聲明的返回類型,但不包含return語句。這裏有一個例子:

class DizzyDean { 
    int pitch() { throw new RuntimeException("90 mph?!"); } 
} 
+0

JLS來救援! \ O / – Bombe 2009-12-24 21:50:41

7

如果您問是否可以使用無限循環,答案是肯定的。有很多情況下你想要永遠運行的東西,儘管循環通常會在某個時候終止。

至於你的問題:「Java可以識別循環將無限?」答案是,計算機不可能有算法來確定程序是否會永久運行。閱讀關於:Halting Problem

讀了一會兒,你的問題也在問爲什麼doSomething()函數不會抱怨它沒有返回一個int。

有趣的是下面的代碼不會編譯。

public class test { 
    public static int doSomething() {     
    //while(true); 
    boolean test=true; 
    while(test){ 


    } 
    } 
    public static void main(String[] args) {    
    doSomething();  
    } 
} 

這表明,我認爲,作爲停機問題的維基頁面提示,它是不可能有作爲一個算法,以確定是否所有的問題將終止,但這並不意味着有人不加簡單情況下:

while(true); 

java規範。我上面的例子稍微複雜一點,所以Java不能將它記爲無限循環。真的,這是一個奇怪的邊緣情況,但它只是爲了編譯。也許有人會嘗試其他組合。

編輯:不是無法訪問的代碼的問題。

import java.util.*; 

public class test { 
    public static int doSomething() {     
    //while(true); 
    while(true){ 
    System.out.println("Hello"); 
    } 
    } 
    public static void main(String[] args) {    
    doSomething();  
    } 
} 

上面的作品,所以while(true);不會被編譯器視爲無法訪問,否則會引發編譯時錯誤!

+2

你的答案有誤導性。計算機程序不可能識別任意程序是否停止,但檢查「特定程序」是否停止絕對不是不可能的。當然,'while(true);'沒有'break'或'goto'語句是一個無限循環的事實可以由編譯器檢查。 – 2009-12-24 15:00:30

+0

是的,我糾正了上述情況。 – Alex 2009-12-24 15:00:53

+0

boolean test = true; (測試) 不一定是無限循環。另一個線程可能會改變'test'的值。 – 2009-12-25 18:58:12

1

是的,您可以在某些線程中看到這些「無限」循環,例如在某個端口上偵聽傳入消息的服務器線程。

0

重讀這個問題之後....

Java理解while(true);永遠不能完成,它不完全追蹤下面的代碼。

boolean moo = true; 
while (moo); 

此信息是否有用?疑。

+0

那究竟是「在做什麼」? – 2009-12-24 15:05:50

+0

這不一定是無限循環。另一個線程可能會將'moo'設置爲false。 – 2009-12-25 18:59:34

13

Java規範定義了一個名爲Unreachable statements的概念。您的代碼中不允許有無法訪問的語句(這是編譯時錯誤)。根據定義,while(true);語句使以下語句無法訪問。在Java中的while(true);語句之後,您甚至不允許使用return語句。請注意,儘管在通用情況下Halting problem是不可判定的,但「不可訪問的聲明」的定義比僅僅停止更爲嚴格。它正在決定非常具體的案例程序肯定不會停止。編譯器理論上無法檢測到無限循環和無法訪問的語句,但它必須檢測規範中定義的特定情況。

+0

但它編譯。另外:while(true){// code}也編譯,而不返回int! – Alex 2009-12-24 15:41:15

+3

'while(true)'is not unreachable(顯然!)。 'while(true)'後面的任何語句都無法訪問。 – 2009-12-24 21:05:26

+0

Pavel:對。當然,這就是我的意思。 – 2009-12-24 21:10:13

1

所以我的問題是:這是在某處Java規範

該方案是根據規範合法的Java。 JLS(和Java編譯器)認識到該方法不能返回,因此不需要return聲明。事實上,如果在循環之後添加return語句,那麼Java編譯器會給你一個編譯錯誤,因爲return語句是不可訪問的代碼。

並且有沒有這種行爲可能有用的情況?

我不這麼認爲,除非可能在模糊的單元測試中。

我偶爾會編寫永遠不會返回(通常)的方法,但是將當前線程置於不可中斷的無限繁忙循環中很少有意義。

0

你可能會實現一個通用的接口,例如,儘管該方法可以用一個有意義的退出並返回值,您的特定的實現是一個有用的無限循環(例如,網絡服務器),它從來沒有的情況下它應該退出,即觸發返回值的任何操作。

此外,關於像boolean x = true; while (x);代碼,這將編譯上給出一個x修改final。我不知道如何,但我可以想象這是Java選擇合理簡單的常量表達式分析(這需要直截了當地定義,因爲依賴於程序的這種拒絕,它是語言定義的一部分)。

0

關於無法陳述一些注意事項:

java2 specs「不到的語句」的描述中可以找到。特別有趣下面的句子:

除特殊處理的,並語句,其條件表達式的常量值爲true,表達式的值不考慮流程分析中的

所以,顯然無法從while (true);退出無限循環。但是,還有兩個選項:change cached values或直接入侵類文件或JVM操作內存空間。