2013-08-22 107 views
0

我期望這個程序給我編譯錯誤,但它編譯成功,我運行時得到一個運行時異常。異常而不是編譯器錯誤

class substr11 
{ 

public static void main(String args[]) 
{ 

String s = "abcde"; 

System.out.println(s.substring(1,-1)); 

} 


} 

編譯器錯誤應該能夠解析(字符串在人體自身初始化),並發現這串操作會導致編譯錯誤吧? 有人可以告訴我爲什麼它沒有拋出編譯錯誤?

異常在線程 「主」 java.lang.StringIndexOutOfBoundsException:字符串IND 前超出範圍:-2 在java.lang.String.substring(未知來源) 在substr11.main(substr11.java:9 )

+1

爲什麼使用-1? – Gerret

+4

因爲編譯器不是一個全面的靜態分析工具? –

+0

@OliCharlesworth我只想知道它是否有意義。我可能會錯誤地理解他的問題,我認爲他可以使用-1來引導外線 – Gerret

回答

3

編譯錯誤是當編譯器不能編譯代碼(語法錯誤,缺少符號等..)。

如預期是不是在你的程序中,你傳遞兩個int s到String#substring的情況下,你不會錯過任何東西(沒有缺課,支架都OK,分號像預想的那樣),那麼爲什麼要編譯器護理?

你得到一個異常如果代碼編譯墜毀由於一些異常(如ArrayIndexOutOfBounds)。

1

編譯器從不解析或優化到方法調用。即使子字符串操作可能無效且具有硬連線參數,但它並不重要,因爲它不會分析整個方法調用。

該調用可能會產生副作用,或者僅在可能包含實例,靜態變量甚至庫選擇的複雜條件集下拋出運行時異常。

編譯錯誤可能包括無效的語法,但不是這樣的事情。該方法調用是有效的。也許某個字符串可以將這組參數用於其子字符串方法。編譯器不會對該字符串執行復雜的分析。

如果這樣做,編譯將會花費很長時間,並且會出現許多錯誤。

0

騰出一些時間來閱讀規格JLS#11.2

例外

Java編程語言要求程序包含處理程序檢查的異常,這會導致從方法的執行或編譯時檢查構造函數。對於可能導致的每個檢查異常,方法(§8.4.6)或構造函數(§8.8.5)的throws子句必須提及該異常的類或該異常的類的超類之一(§ 11.2.3)。

此編譯時檢查異常處理程序的存在旨在減少未正確處理的異常數量。在throws子句中命名的checked異常類(§11.1.1)是實現者與方法或構造函數的用戶之間的契約的一部分。重寫方法的throws子句可能不指定此方法將拋出任何被重寫的方法不允許的檢查的異常,通過其throws子句拋出(第8.4.8.3節)。

而且hirarchy

java.lang.Object 
    java.lang.Throwable 
    java.lang.Exception 
    java.lang.RuntimeException 
     java.lang.IndexOutOfBoundsException 
     java.lang.StringIndexOutOfBoundsException 

唯一的例外發生在運行時沒有在編譯時除外。

1

代碼中沒有編譯時錯誤。對substring()的調用取兩個int,這是對substring method的有效調用。

編譯器不檢查字符串的內容,所以它沒有看到這會在運行時拋出異常。

就編譯器看來,s變量只被假定爲String,其內容沒有任何假設。在這種情況下,它被分配了一個常量值,但它可能是無法估量的,比如數據庫查詢結果或其他東西。這同樣適用於函數的參數int

總結一下,在他的回答中指出的六分法,編譯器不會對輸入執行復雜的分析。開發人員負責對輸入進行必要的檢查,以避免運行時或檢查異常,或相應地捕獲它們。

0

不要混淆編譯器作業,簡而言之就是將代碼轉換爲低級指令和代碼執行。在你的情況下,程序應該調用很多子函數來「理解」你的代碼中存在邏輯錯誤。

1

編譯器不知道該操作的結果是什麼。他知道s.substring()需要2個int參數,他確保該調用是正確的(s.substring(1,-1)必須是int參數)。

0

有人能告訴我爲什麼它沒有拋出編譯錯誤嗎?

因爲它不是一個編譯錯誤,並有權Java程序員(和他們的經理!)依靠這個不是編譯錯誤!

在另一個世界中,Java語言可能已指定爲以要求(或允許)編譯器嘗試評估substring調用,並將其標記爲錯誤。

但是,在這個世界上,Java編譯器只允許爲「常量表達式」(如JLS 15.28中指定的那樣)做。根據規範,任何包含方法調用的表達式都不是「常量表達式」。因此,在現實中,substring調用必須在運行時進行評估,並且是必須給您一個運行時異常。


那麼爲什麼Java這樣設計呢?

您需要問Java設計師...

...但我認爲它是兩件事的組合:

  • Java 1.0語言必須提前發佈,否則它將錯過市場機會。

  • 然後對向後兼容性有一個首要的要求......以便隨着語言的發展,舊的Java程序將繼續工作。