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