本文介紹的JAVA規則的說明分為3個主要層級,中級是平時開發用的比較多的層級,在今後將陸續寫出其他的規則。遵守了這些規則可以提高程式的效率、使代碼又更好的可讀性等。
(1) 在finally方法裡關掉input或者output 資源
再方法體裡面定義了input或者output流的話,需要在finally裡面把它關掉。
以下這幾種調用不需要遵守這條規則,因為colse()方法不起作用:)
java.io.StringWriter java.io.ByteArrayOutputStream java.io.ByteArrayInputStream
如果再方法返回的時候沒有調用close()方法來釋放input()和output()的資源的話,會導致一個系統資源泄漏。而且在任何情況下都要確定在返回全調用了close() 方法,包括出現異常的時候。所以需要在finally方法裡面加入這個方法。這樣就保證了在任何情況下都會關閉資源。
錯誤樣本:
public class CIO {
public void method (java.io.File f) {
java.io.FileInputStream fis = null;
try {
fis = new java.io.FileInputStream (f);
fis.read ();
fis.close ();
} catch (java.io.FileNotFoundException e1) {
System.out.println("File not found");
} catch (java.io.IOException e2) {
System.out.println("I/O Exception");
}
// 如果出現異常,這裡就不能保證關閉資源。
}
}
修正後的代碼:
public class CIOFixed {
public void method (java.io.File f) {
java.io.FileInputStream fis = null;
try {
fis = new java.io.FileInputStream (f);
fis.read ();
} catch (java.io.FileNotFoundException e1) {
System.out.println("File not found");
} catch (java.io.IOException e2) {
System.out.println("I/O Exception");
} finally {
if (fis != null) {
try {
fis.close ();
} catch (java.io.IOException e) {
System.out.println("I/O Exception");
}
}
}
}
}
(2) else的注意問題.
一般總認為如果if語句只有一句的話,那麼{}就是可要可不要的了。可是如果if有else嵌套的話,就不一樣了,{}是必需的
錯誤樣本:
if (i < 5)
if (i < 2)
i++;
else
i--;
修改後:
if (i < 5) {
if (i < 2)
i++;
}
else {
i--;
}
(3) 不要再catch()塊裡什麼代碼也不放
在catch()塊裡面放入一些錯誤處理代碼是一個好的習慣。但是如果catch()裡面有有關javadoc 的代碼,那也是可以的。
錯誤樣本:
try {
System.in.read ();
} catch (java.io.IOException e) {
// 錯誤
}
正確:
try {
System.in.read ();
} catch (java.io.IOException e) {
System.out.println("Descriptive error");
}
參考:Joshua Bloch: "Effective Java - Programming Language Guide".
Addison-Wesley, 2001, pp. 187
(4) 不要在if條件裡面附值
如果這樣做的話,系統會報告錯誤。在java的很多條件聲明裡面用附值是很不明智的,而且系統也會報告錯誤。很容易引起異常。遵守這條規者能夠使維護簡單,避免不一致。
錯誤樣本:
if (b = true)
正確的:
if (b == true)
參考:Section 10.4 of http://java.sun.com/docs/codeconv/html/CodeConventions.doc9.html#547
(5) for語句需要迴圈體。
如果沒有{}的話,for語句只會執行一次!
錯誤樣本:
for (i = 0; i < 10; i++) ;
System.out.println (i);
這裡print() 只會執行一次。
正確:
for (i = 0; i < 10; i++) { // FIXED
System.out.println (i);
}
(5) 不要把方法定義成main().
在java裡,main()方法是一個特別的方法。所以在自己定義方法的時候不要定義這樣的名字,以免引起混擾。
(6)不要直接或者間接的定義'Error'和'Throwable'的子類
'java.lang.Error'只在JVM出現反常的時候覆蓋這個方法,如果你定義了直接或者不直接的類繼承了類'Error',也就指出了這個錯誤是JVM內部的,而不是這個類的。所以對於java編譯器來說是不可見的,這樣就不能檢查錯誤的異常處理了。
'java.lang.Throwable'是'java.lang.Exception'和'java.lang.Error'的上級類,使用者如果象定義異常類的話應該繼承'java.lang.Exception'。
錯誤樣本:public class ABC extends Error
正確:public class ABC extends Exception
(7)有關"switch"語句裡面的"case"問題
最好在每一個 “case”裡都定義一個”return”或者“break”來控制不要走到下面的 “case”裡去。如果一個”case”語句在代碼的最後沒有一個”break”或者”return”句,程式就會走到下一個”case”。如果這個”case”是最後一個的話,那就沒什麼問題,如果後面還有”case” 的話,看起來就不太安全了。
錯誤樣本:
switch (i) {
case 1:
x = 10;
break;
case 2:
x = 20;
default:
a = 40;
break;
正確:
switch (i) {
case 1:
x = 10;
break;
case 2: // VIOLATION
x = 20;
break;
default:
x = 40;
break;
(8)建議不要使用'System.getenv ()'
不建議使用'System.getenv ()',這個方法看起來很好用,不過並不是所有的系統都有環境變數的。不用這個方法也可能帶來一些不方便。
錯誤樣本:
void method (String name) {
System.getenv (name); // 可以用其他方法來代替
}
如果不用這個方法,我們可以用其它的方法來代替。比如:'System.getProperty ()’,'getTypeName ()'等,這也可以找到java的系統屬性。
參考:David Flanagan: "Java in a Nutshell". O'Reilly
November, 1999: Third Edition, pp.190-192
(9)不要使用’\n’或者'\r'來分行
這兩個標記看來很普遍,特別是’\n’。我們經常用來作為分行用。但是不同的系統用不同的分行字元,所以這些字元在某些意義上違背了java的平台無關性。
錯誤樣本:
System.out.println("Hello\n" + name);
我們可以用其它的一些方法來代替,比如println(),這個方法在不同的系統平台上都起到相同的作用。後者推薦大家用這個方法:System.getProperty("line.separator")
參考:David Flanagan: "Java in a Nutshell". O'Reilly,
November 1999: Third Edition, pp. 191-192
(10) 使所有的內部類"private".
Java允許一個類包含另外一個類,帶是Java byte code沒有這個概念。類被編譯器解釋成package-private類。從更深的程度來說,包含類的任何內部私人對象能被內部類訪問的也能被同一個包內的其他類訪問。
錯誤樣本:
public class INNER {
class INNER_Class {
void setValue(int i) {
_value = i; // 現在包就可以訪問了
}
}
private int _value;
}
所以需要加上private class INNER_Class
參考:Statically Scanning Java Code: Finding Security Vulnerabilities.
John Viega, Gary McGraw, Tom Mutdosch, and Edward W. Felten
IEEE SOFTWARE September/October 2000
(11)不要使介面序列化
如果一個位元組數組包含了一個被序列化的對象。攻擊者就能讀到這個對象的內部狀態合欄位(包括private的)。
錯誤樣本:
public interface sample extends java.io.Serializable