11.13 為什麼要避免在Java中使用異常作為控制流?

你在Java中使用過異常作為控制流嗎?你也許不應該這麼做。下面就是原因。

為什麼要避免在Java中使用異常作為控制流?

Java是一種通用的編程語言,有很多解決某個問題的方法。然而,有一些最佳實踐需要遵循,也有一些壞的實踐仍然普遍使用。

這些常見的錯誤實踐之一是使用異常作為控制流。這應該避免,原因有二:它降低了代碼作為單位時間響應的性能,並使代碼可讀性降低。

讓我們首先通過查看下面的示例代碼來了解如何使用異常作為控制流。代碼的商業案例是:

 public static int findAge(String name) {
try {
String ageAsString = findUser(name);
return ageAsString.length();
} catch (NameNotFoundException e) {
return 0;
}
}
private static String findUser(String name) {
if(name==null) {
throw new NameNotFoundException();
}
return name;
}

如果客戶端為findAge方法提供非空名稱,則返回名稱的長度,但如果用戶名為空,則findUser方法將拋出NameNotFoundException,在這種情況下,findAge方法將返回0。

一個人如何能毫無例外地重構這段代碼?坦率地說,有多種方法可以做到這一點,但這裡只提供其中一種。

public static int findAgeNoEx(String name) {
String ageAsString = findUserNoEx(name);
return ageAsString.length();
}
private static String findUserNoEx(String name) {
if(name==null) {
return "";
}
return name;
}

為了找出異常對性能的影響,我編寫了以下代碼,這段代碼調用了兩個實現的10萬次,可以看出異常在我的英特爾酷睿i7-3630QM CPU上花費了數千毫秒。

public class ControlFlowWithExceptionOrNot {
public static class NameNotFoundException extends RuntimeException {
private static final long serialVersionUID = 3L;
}
private static final int TRIAL = 10000000;
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
for (int i = 0; i < TRIAL; i++) {
findAgeNoEx(null);
}
System.out.println("Duration :" + (System.currentTimeMillis() - start));
long start2 = System.currentTimeMillis();
for (int i = 0; i < TRIAL; i++) {
findAge(null);
}
System.out.println("Duration :" + (System.currentTimeMillis() - start2));
};
public static int findAge(String name) {
try {
String ageAsString = findUser(name);
return ageAsString.length();
} catch (NameNotFoundException e) {
return 0;
}
}
private static String findUser(String name) {
if (name == null) {
throw new NameNotFoundException();
}
return name;

}
public static int findAgeNoEx(String name) {
String ageAsString = findUserNoEx(name);
return ageAsString.length();
}
private static String findUserNoEx(String name) {
if (name == null) {
return "";
}
return name;
}
}

輸出得出:

Duration :16
Duration :6212

如果我們從可讀性的角度比較這兩個findAge方法,毫無例外的一個是非常清晰的,無論findUser方法返回什麼,都要取它的長度,我們確信findUser方法將返回一個字符串。但是,有一個例外是有點混亂:findUser方法的返回不清楚。它可能返回一個字符串,或者拋出一個異常,並且從方法的簽名來看,它是不可見的。因此,函數式編程範式不歡迎異常。

最後,如果在出現真正的異常情況時使用異常,則會更好。如果對控制流使用異常,則可能會導致性能問題,並且代碼的可讀性可能會降低。

希望這個能幫助你。

另外,麻煩關注一下唄。


分享到:


相關文章: