java常見錯誤列表:
找不到符號(symbol)類X是public的,應該被聲明在名為X.java的文件中缺失類、接口或枚舉類型缺失X缺失標識符非法的表達式開頭類型不兼容非法的方法聲明;需要返回類型數組越界(java.lang.ArrayIndexOutOfBoundsException)字符越界(java.lang.StringIndexOutOfBoundsException)類Y中的方法X參數不匹配缺少return語句精度損失在解析時到達了文件結尾執行不到的語句變量沒被初始化遇見過上面沒有列舉的錯誤?如果有,那就在Piazza上提問吧,要在錯誤專欄(error folder)下吆。
1. 找不到符號(symbol)
當你在代碼中引用一個沒有聲明的變量時一般會報這個錯誤??紤]下面的例子:
12345678910 | public class Test { public static void main(String[] args) { int a = 3 ; int b = 4 ; int c = 20 ; average = (a + b + c)/ 5.0 ; System.out.PRintln(average); } } |
12345 | 1 error found: File: Test.java [line: 7] Error: Test.java:7: cannot find symbol symbol : variable average location: class Test |
在上面的例子中,變量average沒有被聲明——也就是說你需要告訴編譯器average的類型是什么,例如:
1 | double average = (a + b + c)/ 5.0 ; |
此外,當你在代碼中引用一個方法但沒有在方法名后加上括號時也會報這個錯誤,加上括號用以表明引用的是個函數,即使當函數沒有參數時也不能省略括號。例如:
123456789 | public class Test { public static void main(String[] args) { my_method; } public static void my_method() { System.out.println( "Hello, world!" ); } } |
12345 | 1 error found: File: Test.java [line: 7] Error: Test.java:7: cannot find symbol symbol : variable my_method location: class Test |
在上面的例子中,編譯器在main方法中查找名為my_method的變量,實際上,你是想調用一個叫做my_method的方法:
123456789 | public class Test { public static void main(String[] args) { my_method(); } public static void my_method() { System.out.println( "Hello, world!" ); } } |
第三種情況,如果你忘記導入你所使用的包時也會出現這個錯誤。例如,考慮下面這個從用戶那里讀入一個整數的例子:
123456 | public class Test { public static void main(String[] args) { Scanner console = new Scanner(System.in); int n = console.nextInt(); } } |
123456789 | 2 errors found: File: Test.java [line: 3] Error: cannot find symbol symbol: class Scanner location: class Test File: Test.java [line: 3] Error: cannot find symbol symbol: class Scanner location: class Test |
這里的問題是程序必須導入java.util.Scanner(或者java.util.)。否則,編譯器不知道Scanner是什么類型。當你在處理文件的輸入/輸出時,如果忘記導入java.util.Arrays或者java.io.,也會遇到這個錯誤。
1234567 | import java.util.*; public class Test { public static void main(String[] args) { Scanner console = new Scanner(System.in); int n = console.nextInt(); } } |
最后,當我們在使用大小敏感的變量名時也會遇到這個錯誤。Java中所有的標識符(identifiers)都是區分大小寫的。這就意味著,如果我們聲明了一個名為average的變量,然后在后面用Average引用它時,編譯器就會報找不到Average這個變量的錯誤。
2. 類X是public的,應該被聲明在名為X.java的文件中
在一個Java程序中,如果類名與文件名不匹配時會報這個錯。例如,下面這個Foo.java程序:
12345 | public class Bar { public static void main(String[] args) { System.out.println( "Hello, world!" ); } } |
123 | 1 error found: File: Foo.java [line: 1] Error: class Bar is public, should be declared in a file named Bar.java |
由于Foo與Bar不匹配,這段代碼會編譯失敗。修改這個錯誤,我們既可以修改類名,也可以修改文件名。
3. 缺失類、接口或枚舉類型
這個錯誤是一種與大括號有關的錯誤,一般來說,這個錯誤發生在程序最后有太多大括號時;例如:
123456 | public class Test { public static void main(String[] args) { System.out.println( "Hello!" ); } } } |
123 | 1 error found: File: Test.java [line: 6] Error: class, interface, or enum expected |
一種找出這種錯誤的方式是正確的縮進代碼(因為這種錯誤總是與大括號有關)。我們可以在Dr.java中按組合鍵CTRL-A(去選中這個程序),然后按TAB鍵(來正確地縮減代碼)。在我們上面的實例代碼中,程序的最后有兩個大括號,這在一個合法的程序中是不可能出現的。因此,我們僅僅去掉一個大括號就能夠讓程序正確的編譯。
12345 | public class Test { public static void main(String[] args) { System.out.println( "Hello!" ); } } |
4. 缺失X
當編譯器檢查到代碼中缺失字符時會出現”缺失X”這種形式的錯誤,錯誤信息會告訴你在哪行缺失了哪個字符,考慮下面的程序:
123456789 | public class Test public static void main(String[] args) { my_method(); } public static void my_method() { System.out.println( "Hello, world!" ) } } |
12345 | 2 errors found: File: Test.java [line: 1] Error: Test.java:1: '{' expected File:.java [line: 7] Error: Test.java:7: ';' expected |
這個錯誤信息告訴你在第1行缺失了一個大括號,在第7行缺失了一個分號。解決這種錯誤很簡單——只需把缺失的字符在正確的位置上補上即可。
123456789 | public class Test { public static void main(String[] args) { my_method(); } public static void my_method() { System.out.println( "Hello, world!" ); } } |
5. 缺失標識符
當把代碼寫在了方法外時會出現這個錯誤;這種錯誤一般也是由大括號引起的??紤]下面的例子:
1234567 | public class Test { System.out.println( "Hello!" ); public static void main(String[] args) { System.out.println( "World!" ); } } |
12345 | 2 errors found: File: Test.java [line: 2] Error: <identifier> expected File: Test.java [line: 2] Error: illegal start of type |
在這種情況下,很明顯第一個打印語句應該放在main方法里面,這樣才能通過編譯。然而,當我們的程序中有多于一個方法并且大括號也不匹配時,這種“缺失標識符”的錯誤就不容易被發現了:
123456 | public class Test { public static void main(String[] args) { System.out.println( "Hello!" );} System.out.println( "World!" ); } } |
1234567 | 3 errors found: File: Test.java [line: 4] Error: <identifier> expected File: Test.java [line: 4] Error: illegal start of type File: Test.java [line: 6] Error: class, interface, or enum expected |
在上面的代碼中多了一個大括號,但是因為代碼沒有正確的縮進,所以很難找出這個錯誤。這樣使得main方法在打印“hello”語句后就結束了,這樣打印“world”的語句就變成方法以外的代碼了。修改這個錯誤的方式十分簡單——只需要把第三行的大括號刪除就可以了:
123456 | public class Test { public static void main(String[] args) { System.out.println( "Hello!" ); System.out.println( "World!" ); } } |
6. 非法的表達式開頭
當編譯器遇到一條不合法的語句時會報“非法的表達式開頭”這種錯誤??紤]下面的例子:
123456789 | public class Test { public static void main(String[] args) { my_method(); public static void my_method() { System.out.println( "Hello, world!" ); } } |
1234567891011 | 5 errors found: File: Test.java [line: 6] Error: Test.java:6: illegal start of expression File: Test.java [line: 6] Error: Test.java:6: illegal start of expression File: Test.java [line: 6] Error: Test.java:6: ';' expected File: Test.java [line: 6] Error: Test.java:6: ';' expected File: Test.java [line: 9] Error: Test.java:9: reached end of file while parsing |
這里,缺少了一個關閉main方法大括號。由于main方法沒有被關閉,編譯器把調用my_method方法之后的代碼也當作main方法的一部分。然而,后面的代碼是public static void my_method() {,很顯然,這在一個方法內不合法。
“非法的表達式開頭”這種錯誤不如我們上面提到的“××缺失”這種信息有幫助。對于這種錯誤(以及很多其他一些錯誤),非常有必要檢查一下出錯代碼前面的那幾行。對于上面那個例子,我們只需要在編譯器報錯的那行前面加上大括號關閉main方法就可以了。重新編譯,所有的錯誤都解決了。
123456789 | public class Test { public static void main(String[] args) { my_method(); } public static void my_method() { System.out.println( "Hello, world!" ); } } |
7. 類型不兼容
當你的程序在處理類型相關的問題時會報這個錯。我們可以對一些類型進行相互轉化,例如,你可以輕松把一個char類型轉為int類型,反之亦然;你也可以通過向上轉型把一個double類型轉為int類型。但是,你不能把基本類型與像String這樣的對象進行相互轉換。例如:
12345 | public class Test { public static void main(String[] args) { int num = "Hello, world!" ; } } |
12345 | 1 error found: File: Test.java [line: 3] Error: Test.java:3: incompatible types found : java.lang.String required: int |
一般來說,你不能像解決其他一些錯誤一樣解決這種錯誤。這不是一種語法錯誤,而是一種關于類型的邏輯錯誤。把一個String類型轉為int類型一般來說都是毫無意義。但是,在一些應用中,你可能需要把String類型轉為int類型,比如,當這個字符串代碼一個數字時:
12345 | public class Test { public static void main(String[] args) { int num = "500" ; } } |
12345 | 1 error found: File: Test.java [line: 3] Error: Test.java:3: incompatible types found : java.lang.String required: int |
解決這種錯誤一般采用這樣的方法:借助于Java中像Integer這樣的類,這些基本類型的包裝類中有能接受字符串類型的參數的方法,這樣就把字符串類型轉為整型了:
12345678910111213141516171819202122232425 | public class Test { public static void main(String[] args) { int num = Integer.parseInt(" 500 "); } } ``` 但是,這種解決“類型不兼容”錯誤的方案是一種例外,不是什么規則,因為這種錯誤一般來自于邏輯上的錯誤。 <a name= "invalid-method" /></a> ### 8 . 非法的方法聲明;需要返回類型 在Java中的每個方法都要求明確的聲明返回類型,即使這個方法什么也不返回,也要用 void 進行標識,就像main方法那樣。 當一個方法沒有聲明返回類型時,會出現這種錯誤: <pre class ="brush: java; gutter: true ; first-line: 1 ; highlight: []; html-script: false "> public class Test { public static void main(String[] args) { int x = getValue(); System.out.println(x); } public static getValue() { return 10 ; } } |
123 | 1 error found: File: Test.java [line: 7] Error: Test.java:7: invalid method declaration; return type required |
解決這種問題,在方法聲明處加上合適的返回類型即可:
12345678910 | public class Test { public static void main(String[] args) { int x = getValue(); System.out.println(x); } public static int getValue() { return 10 ; } } |
9. 數組越界(java.lang.ArrayIndexOutOfBoundsException)
當你使用不合法的索引訪問數組時會報數組越界這種錯誤,數組arr的合法錯誤范圍是[0, arr.length-1];當你訪問這之外的索引時會報這個錯。例如:
12345678 | public class Test { public static void main(String[] args) { int [] arr = { 1 , 2 , 3 }; for ( int i = 0 ; i <= arr.length; i++) { System.out.println(arr[i]); } } } |
1234567 | java.lang.ArrayIndexOutOfBoundsException: 3 at Test.main(Test.java:5) at sun.reflect.NativeMethodaccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:272) |
這種錯誤很像我們下面即將說的字符串索引越界,這種錯誤的錯誤信息后面部分與錯誤不大相關。但是,第1行就告訴我們錯誤的原因是數組越界了,在我們上面的例子,非法的索引值是3,下面一行的錯誤信息告訴你錯誤發生在Test類的第5行上,在main方法之內。
在上面的例子中,因為我們循環過多導致出現這個錯誤,循環索引i最大可以為4,而4超過了數組的長度,因此越界了。相反,i的上界應該使用<或者相同效果的語句來界定。
12345678 | public class Test { public static void main(String[] args) { int [] arr = { 1 , 2 , 3 }; for ( int i = 0 ; i < arr.length; i++) { System.out.println(arr[i]); } } } |
當處理數組越界時,打印出遍歷數組的索引十分有幫助,這樣我們就能夠跟蹤代碼找到為什么索引達到了一個非法的值。
10. 字符串索引越界(java.lang.StringIndexOutOfBoundsException)
當你在程序中去訪問一個字符串的非法索引時會報字符串索引越界這個錯誤。一個String的合法索引范圍是[0,str.leng()-1];當你訪問這之外的索引時會報這個錯。例如:
123456789 | public class Test { public static void main(String[] args) { String str = "Hello, world!" ; String a = str.substring(- 1 , 3 ); String b = str.charAt(str.length()); String c = str.substring( 0 , 20 ); } } |
12345678 | java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.substring(Unknown Source) at Test.main(Test.java:5) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:271) |
這種錯誤的錯誤信息后面部分與錯誤不大相關。但是,第1行就說明了錯誤的地方是字符串的索引,在我們這個例子,非法的索引是-1,下面一行錯誤信息告訴我們這個錯誤是在執行substring方法時拋出的,發生錯誤的位置是Test類的第5行。這種與錯誤相關的程序軌跡告訴我們程序是在調用哪個方式時出的錯,這樣我們就能追蹤代碼,并最終改正它。
值得注意的是,上面程序中的a,b,c都會拋出這種錯誤,但是程序在遇到第一個錯誤時就被迫終止了。
這不是編譯時的錯誤,而是運行時的錯誤。換句話說,編譯器能正確編譯這段程序因為它只是在邏輯上有錯,此外,在程序運行之前,我們也沒法預料是否會有錯誤發生。解決這種錯誤,我們需要改正程序的邏輯來保證沒有地方訪問非法的索引。
11. 類Y中的方法X參數不匹配
當你在調用函數時參數數量或順序不對時會報這個錯誤。例如,考慮下面的程序:
123456789 | public class Test { public static void main(String[] args) { myMethod( 1.0 , 2 , "Hello!" ); } public static void myMethod( double d, String s, int x) { System.out.println(s + " " + d + " " + x); } } |
123456 | 1 error found: File: Test.java [line: 3] Error: method myMethod in class Test cannot be applied to given types; required: double,java.lang.String,int found: double,int,java.lang.String reason: actual argument int cannot be converted to java.lang.String by method invocation conversion |
這種錯誤的錯誤信息非常有幫助?!皉equired”這一行錯誤信息告訴我們方法的參數是什么,方法的參數列表在這后面。在上面的例子中,myMethod方法的參數先后順序應該是double類型、String類型,最后是一個int類型的變量。錯誤信息的下一行(found開頭的這一行)告訴我們程序在調用這個方法時用了什么樣的參數。在上面的例子中,是一個double類型,一個int類型,最后是一個String類型的變量,很顯然順序是不對的。
解決這種錯誤,我們需要保證方法的參數個數和類型與函數聲明時都一致才行。
123456789 | public class Test { public static void main(String[] args) { myMethod( 1.0 , "Hello!" , 2 ); } public static void myMethod( double d, String s, int x) { System.out.println(s + " " + d + " " + x); } } |
12. 缺少return語句
當你聲明一個方法有返回值但是沒有寫return語句時會報這個錯誤。例如:
12345678910 | public class Test { public static void main(String[] args) { int x = twice( 5 ); System.out.println(x); } public static int twice( int x) { int value = 2 * x; } } |
123 | 1 error found: File: Test.java [line: 9] Error: Test.java:9: missing return statement |
我們通過函數聲明告知編譯器twice方法會返回一個int值,但是我們沒有寫return語句:
1234567891011 | public class Test { public static void main(String[] args) { int x = twice( 5 ); System.out.println(x); } public static int twice( int x) { int value = 2 * x; return value; } } |
在某些if條件句中,編譯器也會認為函數沒有返回值。像下面這個例子:
12345678910111213141516 | public class Test { public static void main(String[] args) { int x = absVal(- 5 ); System.out.println(x); } public static int absVal( int x) { if (x < 0 ) { return -x; } if (x >= 0 ) { return x; } } } |
123 | 1 error found: File: Test.java [line: 15] Error: Test.java:15: missing return statement |
避免這種錯誤,我們可以選擇使用else語句(就像我們在變量沒被初始化一樣),或者我們可以不用第二個if語句,因為我們知道,如果程序能夠執行到這個地方,程序就可以直接返回x了:
1234567891011121314 | public class Test { public static void main(String[] args) { int x = absVal(- 5 ); System.out.println(x); } public static int absVal( int x) { if (x < 0 ) { return -x; } return x; } } |
13. 精度損失
當你把信息保存到一個變量中,而信息量超過了這個變量的所能容納的能力時會報這個錯。最常見的例子是把double類型賦值給int類型。
123456 | public class Test { public static void main(String[] args) { int pi = 3.14159 ; System.out.println( "The value of pi is: " + pi); } } |
12345 | 1 error found: File: Test.java [line: 3] Error: Test.java:3: possible loss of precision found : double required: int |
這個錯誤發生的原因是計算機在存儲double類型時所需的空間是int類型的兩倍。如果你不在乎精度的損失,你可以通過上轉型的方法來告知編譯器:
123456 | public class Test { public static void main(String[] args) { int pi = ( int ) 3.14159 ; System.out.println( "The value of pi is: " + pi); } } |
現在編譯器不會報錯了,但是pi這個變量由于進行了取整,最終值為3。
14. 在解析時到達了文件結尾
當你沒有用大括號關閉你的程序時會出現這個錯誤。錯誤信息明確的指出編譯器在沒有明確程序該結束時就到達了文件的結尾。例如:
12345678 | public class Test { public static void main(String[] args) { my_method(); } public static void my_method() { System.out.println( "Hello, world!" ); } |
123 | 1 error found: File: Test.java [line: 9 ] Error: Test.java: 9 : reached end of file while parsing |
解決這個錯誤,我們只需要在最后加上關閉程序的大括號(“}”)即可。有時僅僅在文件末尾缺少了一個大括號,但也有可能是在程序的中間少寫或多寫了大括號的緣故。
一種調試的方法是用快捷鍵CTRL-A + TAB來正確的縮減你的代碼。由于程序的問題與大括號有關,這樣代碼就不能夠正確的縮進。找到程序中第一個縮進不正確的地方,這就是錯誤產生的地方。
一旦大括號正確的匹配上,編譯器就不會報錯了:
123456789 | public class Test { public static void main(String[] args) { my_method(); } public static void my_method() { System.out.println( "Hello, world!" ); } } |
15. 執行不到的語句
當編譯器檢測到某些語句在整個程序流程中不可能被執行到時會報這個錯。這個錯誤經常是由return或break后的語句所導致的。例如:
123456789101112 | public class Test { public static void main(String[] args) { int value = twice( 5 ); System.out.println(value); } public static int twice( int x) { int twice = 2 * x; return twice; System.out.println( "Returning " + twice); } } |
12345 | 2 errors found: File: Test.java [line: 10] Error: Test.java:10: unreachable statement File: Test.java [line: 11] Error: Test.java:11: missing return statement |
編譯器報了兩個錯:一個是說System.out.println(“Returning ” + twice);這一行不可能被法執行到,另一個錯誤是因為編譯器假設可以執行print語句,這樣的話我們在它之后也應該有個return語句,但是程序中沒有,所以報這個錯。
解決這個錯誤,我們可以把print語句放到return的前面,這樣程序就能執行了:
123456789101112 | public class Test { public static void main(String[] args) { int value = twice( 5 ); System.out.println(value); } public static int twice( int x) { int twice = 2 * x; System.out.println( "Returning " + twice); return twice; } } |
15. 變量沒被初始化
當你在程序中去引用一個沒有被初始化的變量時會報這個錯。下面看一個非常簡單的例子:
123456789101112 | public class Test { public static void main(String[] args) { int x = 2 ; int y; System.out.println(x + y); } } 1 error found: File: Test.java [line: 5 ] Error: Test.java: 5 : variable y might not have been initialized |
在程序中你沒有告知編譯器y的值,所以y不能被打印,y需要像x一樣被初始化以后才能使用。
在一些更復雜的情形下,if語句可能導致變量沒有被初始化。例如:
123456789101112 | public class Test { public static void main(String[] args) { int x; boolean setX = false ; if (setX) { x = 10 ; } System.out.println(x); } } |
123 | 1 error found: File: Test.java [line: 8] Error: Test.java:8: variable x might not have been initialized |
這里很明顯,x將不能被正確的初始化,因此編譯器報錯。但是,在一些情況下雖然我們能夠很清楚的知道變量能夠被初始化,但是編譯器不能和我們一樣推測出變量是否會被初始化,例如:
12345678910111213141516 | public class Test { public static void main(String[] args) { int x; boolean setToTen = false ; if (setToTen) { x = 10 ; } if (!setToTen) { x = 0 ; } System.out.println(x); } } |
123 | 1 error found: File: Test.java [line: 14] Error: Test.java:14: variable x might not have been initialized |
很明顯,x一定會被兩個if語句中的任意一個賦值,但是編譯器并不能推測出(譯者注:需要在運行時才能知道),一種修改這個錯誤的方式是使用else語句。當使用else語句時,編譯器就有最夠的證據推測出x將被初始化:
1234567891011121314 | public class Test { public static void main(String[] args) { int x; boolean setToTen = false ; if (setToTen) { x = 10 ; } else { x = 0 ; } System.out.println(x); } } |
原文鏈接: cs-people.bu.edu 翻譯: ImportNew.com - 劉 家財譯文鏈接: http://www.importnew.com/12425.html