有用但多疑的十大Java編程技術

在編碼過一段時間後(哎呀,拿我來說,已經20多年了,當你樂享其中時,時間過得飛快),有人已經開始擁抱他們的習慣了。
因爲,你知道…

“會出錯的事情總會出錯”– 墨菲定律

這就是人們擁抱“自衛編程”,也就是多疑的習慣,有時有道理,有時更模糊。可能有一點奇怪當你想到一個人寫這個的時候。
下面是我總結的10大有用但多疑的Java編程技術。開始吧:

1.優先放置字符常量

把String變量放在equals()方法的左邊,對於預防偶然出現的空指針異常來說,從不是一個好主意。

// 錯誤
if (variable.equals("literal")) { ... }

// 正確
if ("literal".equals(variable)) { ... }

這再明顯不過了,把變量放在右邊是更好的版本。

2.不要相信早期的JDK APIs

在Java的早期時代,編程肯定很痛苦。APIs是非常不成熟的,你可能遇到過下面這樣的代碼:

String[] files = file.list();

// 小心
if (files != null) {
    for (int i = 0; i < files.length; i++) {
        ...
    }
}

多疑了?可能吧,但是看看Javadoc:

“如果抽象的pathname沒有指定一個目錄,那麼這個方法會返回null。否則會返回string數組,數組中的每一個string都是該目錄下的文件或目錄。

對了。最好再添加一個檢查,只是爲了確保安全起見。

if (file.isDirectory()) {
    String[] files = file.list();

    // 小心
    if (files != null) {
        for (int i = 0; i < files.length; i++) {
            ...
        }
    }
}

3.不要相信“-1”

我知道這是多疑的。Javadoc中的 String.indexOf()方法是這樣聲明的:

“返回指定字符在字符序列中的第一次出現的位置,如果沒有該字符,返回-1”

所以,-1就能打保票了嗎?不能,考慮下面情況:

// 錯誤
if (string.indexOf(character) != -1) { ... }

// 正確
if (string.indexOf(character) >= 0) { ... }

誰知道呢。可能在某些情況下他們還需要繼續編碼呢。另一個字符串可能包含是否檢查大小寫,空串(返回0),空值(異常)等情況,
這些都可能是一個返回-2的好例子,誰知道呢。

畢竟,我們討論過無數次關於null的問題。爲什麼我們不開始討論-1呢?在某種程度上,null也是基本數據類型的可選值嗎?

4.避免意外賦值

假定下面是JavaScript,但是也讓我們對這種語言多疑。

// 糟糕
if (variable = 5) { ... }

// 好點 (因爲會引發一個錯誤)
if (5 = variable) { ... }

// 故意 (記住. 多疑的JavaScript: ===)
if (5 === variable) { ... }

再一次,如果你的等式中有常量,把它放到左邊。如果你沒把另一個=號加下,在這裏你就可能意外的犯錯。

5.檢查null和length

無論什麼時候遇到一個集合,數組等類型,確保它是存在且非空的。

// 錯誤
if (array.length > 0) { ... }

// 正確
if (array != null && array.length > 0) { ... }

你永遠不知道這些數組來自哪裏。可能來自早期的Java APIs。

6.所有的方法都是final的

你能告訴我所有你想要的開閉原則,那是胡說。我不相信你(正確的繼承了我的類)並且我不相信我自己(沒有意外繼承我的類)。
這就是爲什麼沒有顯式的使用子類型的方法都是final的。

// 錯誤
public void boom() { ... }

// 正確,不能更改。
public final void dontTouch() { ... }

是的,這個方法是final的。如果這對你不起作用的話,修補它或重寫字節碼。或者發送一個特性請求。
儘管我確定你想要重寫的意圖不是一個好主意。

7.所有的變量和參數是final的

正如我剛纔說到的,我不相自己。(不會意外的重寫我的值)。既然都這麼說了,我完全不相信我自己了。因爲…

這裏寫圖片描述

這也是爲什麼所有的變量和參數都要做成final的原因。

// 錯誤
void input(String importantMessage) {
    String answer = "...";

    answer = importantMessage = "LOL accident";
}

// 正確
final void input(final String importantMessage) {
    final String answer = "...";
}

好,我承認。這個我沒有經常應用在實際中,儘管,我真的應該使用。

8.重載時不要相信範型

// 錯誤
<T> void bad(T value) {
    bad(Collections.singletonList(value));
}

<T> void bad(List<T> values) {
    ...
}

// 正確
final <T> void good(final T value) {
    if (value instanceof List)
        good((List<?>) value);
    else
        good(Collections.singletonList(value));
}

final <T> void good(final List<T> values) {
    ...
}

因爲,你的用戶,他們會像這樣使用:

// 這個類庫真爛
@SuppressWarnings("all")
Object t = (Object) (List) Arrays.asList("abc");
bad(t);

相信我。我看見過這種情況。包括像下面這樣的:

這裏寫圖片描述

還是多疑點好。

9.在switch上永遠拋出默認值

// 錯誤
switch (value) {
    case 1: foo(); break;
    case 2: bar(); break;
}

// 正確
switch (value) {
    case 1: foo(); break;
    case 2: bar(); break;
    default:
        throw new ThreadDeath("That'll teach them");
}

因爲當value==3的那一刻,肯定會發生錯誤。不要說枚舉,因爲枚舉也會發生這種情況。

10.switch要用大括號

事實上,對於那些喝醉了或打賭輸了的人來說,switch是最邪惡的聲明瞭。參考下面例子:

// 錯誤,不編譯
switch (value) {
    case 1: int j = 1; break;
    case 2: int j = 2; break;
}

// 正確
switch (value) {
    case 1: {
        final int j = 1;
        break;
    }
    case 2: {
        final int j = 2;
        break;
    }

    // 記住
    default: 
        throw new ThreadDeath("That'll teach them");
}

在switch聲明內,在所有的case聲明中只有一個範圍定義。事實上,這些case聲明甚至不是真正的聲明,它們更像是switch要被調用時的標籤。

總結

多疑編程有時看起來有點奇怪,當經常這樣編碼時結果就是比實際需要的有一點冗餘。你可能認爲,“這種情況永遠不可能發生”,但正如我之前所說的。在經過20左右的編程後,你只是不想再修復那些愚蠢且沒必要存在的小錯誤,而只是因爲古老有缺陷的語言造成的。
因爲你懂的…

現在,輪到你了!

你在編程中最多疑的怪癖是什麼?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章