建議1:不要在常量和變量中出現易混淆的字母
1、包名全小寫,類名首字母大寫,常量全部大寫並用下劃線分隔,變量纔有駝峯命名法
2、舉例(long類型數值後面小寫l 和大寫L的影響)
public class TestDemo {
public static void main(String[] args) {
long i = 1l;
// long i = 1L;
System.out.print("i * 2 = " + (i + i))
}
}
此處,容易得出結果是22,真正結果是 2。
比如字母“o” 和 數字 0。
建議2:莫讓常量蛻變成 變量
常量一般加了 final 和 static 修飾符,基本不可能二次賦值。但下面有個特殊例子:
public class TestDemo {
public static void main(String[] args) {
System.out.print("變化的常量: " + Const.RAND_CONST)
}
}
// 接口常量
interface Const {
// 變化的常量
public final static int RAND_CONST = new Random().nextInt();
}
注意:務必讓常量的值在運行期保持不變。
建議3:三元操作符的類型務必一致
舉例:
public class TestDemo {
public static void main(String[] args) {
int i = 80;
String s1 = String.valueOf(i < 100 ? 90 : 100); // s1:90
String s2 = String.valueOf(i < 100 ? 90 : 100.0); // s2:90.0
System.out.print("s1 等於 s2: " + s1.equals(s2)); // false
}
}
此處包含了 隱式類型轉換(int -> float),所以二者 不相等。
建議4:避免帶有變長參數的方法重載
方法重載也叫(overload):就是在同一個類中,方法的名字相同,參數列表不同(順序不同、個數不同、類型不同),實現相似的功能,與修飾符、返回值類型無關。我們會覺得方法調用的時候就像調用一個方法一樣。
方法重寫也叫方法覆蓋(override):首先存在繼承的關係中,子類繼承父類並重寫父類的屬性、方法。方法名字相同,參數列表一致、返回值類型一致或父類返回類型的子類類型、修飾符不能縮小範圍。子類不能重寫構造方法、屬性、靜態方法、私有方法。
舉例:
public class TestDemo {
// 簡單折扣
public void calPrice(int price, int discount) {
float money = price * discount / 100.0F;
System.out.println("簡單折扣後價格:" + formatCurrency(money));
}
// 複雜折扣
public void calPrice(int price, int... discount) {
float money = price;
for(int count : discount) {
money = money * count / 100;
}
System.out.println("複雜折扣後價格:" + formatCurrency(money));
}
private String formatCurrency(float price) {
return NumberFormat.getCurrencyInstance().format(price / 100);
}
public static void main(String[] args) {
TestDemo test = new TestDemo();
// 75 折
test.calPrice(49900, 75);
}
}
此處,重載方法也是可以運行的。實際調用的方法是第一個。
建議5:別讓 null 值 和 空值威脅到 變長方法
舉例:
public class TestDemo {
public void methodA(String str, Integer... value){}
public void methodA(String str, String... value){}
public static void main(String[] args) {
TestDemo test = new TestDemo();
test.methodA("test", 0);
test.methodA("test", "haha");
test.methodA("test"); // 編譯報錯,因爲2個方法均滿足,編譯器無法決定使用哪一個
test.methodA("test", null); // 編譯報錯,因爲2個方法均滿足,編譯器無法決定使用哪一個
}
}
可以修改爲這樣調用:
String[] arr = new String[1];
arr[0] = null;
test.methodA("test", arr);
建議6:覆寫變長方法也循規蹈矩
public class TestDemo {
public static void main(String[] args) {
// 向上轉型
Base base = new Sub();
base.fun(100, 50);
// 不轉型
Sub sub = new Sub();
sub.fun(100, 50); // 編譯報錯
}
}
// 基類
class Base {
void fun(int price, int... discounts){
System.out.println("Base fun");
}
}
// 子類
class Sub extend Base {
@Override
void fun(int price, int[] discounts){
System.out.println("Sub fun");
}
}
注意:方法重寫(覆寫)的方法參數需與父類相同,不僅僅是類型、數量、順序,還包括顯示形式。
建議7:警惕自增的陷阱
public class TestDemo {
public static void main(String[] args) {
int count = 0;
for(int i = 0; i< 10; i++) {
count = count++;
}
System.out.println("count= " + count);
}
}
此處輸出count=0。
首先將count的值拷貝到臨時變量區,然後對count加1,最後返回臨時變量區的值,將count重置爲0。
建議9:少用靜態導入
import static java.lang.Double.*;
import static java.lang.Math.*;
import static java.lang.Integer.*;
import static java.text.NumberFormat.*;
public class Test {
public static void main(String[] args) {
double s = PI * parseDouble(1);
NumberFormat nf = getInstance();//此處可閱讀性差,應改爲 NumberFormat.getInstance()
}
}
注意:
- 不建議使用 *(星號)來導入靜態元素;
- 方法名是具有明確、清晰表象意義的工具類。
建議10:不要在本類中覆蓋靜態導入的變量和方法
import static java.lang.Math.PI;
import static java.lang.Math.abs;
public class Test {
// 常量名與靜態導入的 PI 相同
public final static String PI = "祖沖之";
// 方法名 與 靜態導入的方法相同
public static int abs(int value) {
return 0;
}
public static void main(String[] args) {
System.out.println("PI=" + PI); // 輸出“祖沖之”
System.out.println("abs()=" + abs(-100)); // 輸出 0
}
}
此處並沒有調用 Math的方法,而是調用 本類(Test)的常量和方法。
因爲編譯器有一個“最短路徑”原則:如果能夠在本類中找到變量、常量和方法,就不會到其他包或父類、接口中查找,以確保本類的屬性、方法優先。
建議11:養成良好習慣,顯示聲明 UID
我們將一個類 實現 Serializable 接口時,常常編譯器會提醒我們加上 serialVersionUID。如果我們不指定,則會在編譯時自動生成。此後,我們進行反序列化時,程序會比較 serialVersionUID的值。相同則可以反序列化,不同則拋出異常(InvaildClassException)。
所以,請顯示聲明 serialVersionUID。
建議12:避免用序列化類在構造函數中爲不變量賦值
不知道怎麼說,那就記住它吧。
注意:
- 反序列化時構造函數不會被執行。
- 在序列化類中,不要使用構造函數爲 final 變量賦值。
建議13:避免爲 final 變量複雜賦值
注意:此建議可以結合建議12來看,是其拓展。總結如下:
- 在序列化類中,不要使用構造函數爲 final 變量賦值。
- 在序列化類中,不要使用方法返回值爲 final 變量賦值。
建議14:使用序列化類的私有方法巧妙解決部分屬性持久化問題
部分屬性持久化問題,常見的解決方法是在不需要持久化的的字段前加 transient 關鍵字即可。
建議15:break萬不可忘
未完,待續。。。(PS:歡迎大家補充)