[英]Why should I use Exception handlings in Java?
我讀了許多關於Java異常處理的文章,但我的確得到了滿意的答復。為什么要將它們放入我的代碼中?
Java異常處理使錯誤處理代碼與我的業務邏輯分離
以下代碼段在哪里分隔錯誤處理?
public int division(int divident, int divisor) {
int result = 0;
try {
result = divident / divisor;
} catch (ArithmeticException e) {
System.out.println("Divisor must not be zero !");
}
return result;
}
3. Java的默認異常處理使得在標准輸出中顯示異常信息並終止程序。 我是否自己使用異常處理來避免終止程序?
這是三個問題,但這並不是第一次在這里發生。 :-)
是的,您必須處理它們或聲明它們,因為它們是檢查異常。 您必須這樣做的原因是為了使調用您的代碼的代碼知道您的代碼可能失敗的方式(因為您已經聲明了它可能引發的異常)。
該代碼段非常簡單,因此分離和收益並不清楚。 但是,請考慮使用轉換代碼(包括對下級方法的調用)打開兩個流,從一個流復制到另一個流。 您最終將獲得一個包含10-20條語句的方法主體。 無需知道每個I / O語句是否有效,您只需將邏輯包裝在IOException
處理程序中即可,知道任何I / O異常都會從主邏輯跳入處理程序。
這取決於您正在編寫的程序類型,但是通常您會在最適當的級別(通常在程序的多個級別)處理異常。 最外面的級別僅用於處理真正,非常不尋常的不可恢復的異常,要么只是讓默認處理程序執行其操作,要么使用執行類似操作但可能(試圖)記錄故障的包羅萬象的處理程序其他地方(例如日志文件):
public class MyProgram { public static final void main(String[] args) { try { // Run... } catch (Throwable t) { // Handle the fact that something went wrong here, if you can // Usually this would be only for really, really unusual errors, // otherwise you would have handled them earlier } } }
為了強調#2的觀點,請考慮兩種process
方法,一種在Java中帶有異常,而另一種在假設的類似Java的語言中沒有異常:
Java一:
private void process() {
try ( // <== Main logic
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
) { // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != null) { // <== Main logic
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
bw.write(line); // <== Main logic
bw.newLine(); // <== Main logic
} // <== Main logic
} // <== Main logic
}
catch (FileNotFoundException fnfe) { // <== Error handling
// Couldn't find a file // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (IOException ioe) { // <== Error handling
// I/O error // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (Exception e) { // <== Error handling
// Something else went wrong // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
}
假想的類似Java的語言,無一例外:
// THIS IS FAKE, PSEUDO-JAVA
private Errors process() {
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
if (fr == null) { // <== Error handling
return Errors.CantOpenSource; // <== Error handling
} // <== Error handling
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
if (fw == null) { // <== Error handling
br.close(); // <== Error handling
return Errors.CantOpenDest; // <== Error handling
} // <== Error handling
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != IO.END_OF_FILE) { // <== Main logic
if (line == null) { // <== Error handling
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantRead; // <== Error handling
}
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling)
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantWrite; // <== Error handling
}
}
}
bw.close();
br.close();
return Errors.Success;
}
注意:
process
上添加一個,然后new FileReader
等檢查是否為null
,並從讀寫操作等檢查-1。 如果您有興趣,這里是Java程序的完整版本與非真正Java程序的完整版本:
Java的:
import java.io.*;
public class Example
{
private String sourceFileName;
private String destFileName;
public static void main (String[] args) throws java.lang.Exception
{
try {
new Example(args[0], args[1]).process();
}
catch (ArrayIndexOutOfBoundsException npe) {
// This is a bit of an exaggeration, I'd check in advance, since the user not
// supplying arguments isn't really an "exceptional" condition.
System.out.println("Usage: java Example [source file name] [dest file name]");
}
}
public Example(String src, String dest) {
// Similar, these checks would probably be assertions, but I'm making a point...
if (src == null || src.length() == 0) {
throw new IllegalArgumentException("src must be non-null and non-blank");
}
if (dest == null || dest.length() == 0) {
throw new IllegalArgumentException("dest must be non-null and non-blank");
}
this.sourceFileName = src;
this.destFileName = dest;
}
private void process() {
try ( // <== Main logic
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
) { // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != null) { // <== Main logic
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
bw.write(line); // <== Main logic
bw.newLine(); // <== Main logic
} // <== Main logic
} // <== Main logic
}
catch (FileNotFoundException fnfe) { // <== Error handling
// Couldn't find a file // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (IOException ioe) { // <== Error handling
// I/O error // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (Exception e) { // <== Error handling
// Something else went wrong // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
}
private boolean shouldIncludeLine(String line) {
return line.length() != 0;
}
private String transformLine(String line) {
return line.toUpperCase();
}
}
假想的類似Java的語言,無一例外:
// THIS IS FAKE, PSEUDO-JAVA WITHOUT EXCEPTIONS, IT ISN'T REAL
import java.io.*;
public class Example
{
private String sourceFileName;
private String destFileName;
private enum Errors {
Success,
CantOpenSource,
CantOpenDest,
CantRead,
CantWrite
}
public static void main (String[] args) throws java.lang.Exception
{
if (args.length < 2) {
System.out.println("Usage: java Example [source file name] [dest file name]");
}
if (args[0] == null || args[0].length() == 0) {
throw new IllegalArgumentException("src must be non-null and non-blank");
}
if (args[1] == null || args[1].length() == 0) {
throw new IllegalArgumentException("dest must be non-null and non-blank");
}
switch (new Example(args[0], args[1]).process()) {
case Errors.CantOpenSource:
// Handle it
break;
case Errors.CantOpenDest:
// Handle it
break;
case Errors.CantRead:
// Handle it
break;
case Errors.CantWrite:
// Handle it
break;
}
}
public Example(String src, String dest) {
// Not how now this constructor is trusting that it is called with valid arguments
this.sourceFileName = src;
this.destFileName = dest;
}
private Errors process() {
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
if (fr == null) { // <== Error handling
return Errors.CantOpenSource; // <== Error handling
} // <== Error handling
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
if (fw == null) { // <== Error handling
br.close(); // <== Error handling
return Errors.CantOpenDest; // <== Error handling
} // <== Error handling
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != IO.END_OF_FILE) { // <== Main logic
if (line == null) { // <== Error handling
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantRead; // <== Error handling
}
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling)
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantWrite; // <== Error handling
}
}
}
bw.close();
br.close();
return Errors.Success;
}
private boolean shouldIncludeLine(String line) {
return line.length() != 0;
}
private String transformLine(String line) {
return line.toUpperCase();
}
}
1)如果您的代碼無法處理異常,則可以捕獲從API調用引發的已檢查異常,並將其包裝在未檢查異常中。 確保將原始已檢查的異常保存為新未檢查的異常中的原因。
2)您的示例代碼片段並未將錯誤處理與業務邏輯分開,而是將它們組合在一起並混淆了結果。 在這里拋出算術異常而不是傳遞默認值有兩個好處:a)很難區分傳遞標記為錯誤的值和有效計算的結果,b)進一步的業務邏輯步驟可能取決於此處計算的有效值,在這種情況下,無論如何您都將不得不離開當前流,您最好為此使用例外。
3)取決於應用程序。 對於簡單的控制台程序,有時最好的辦法是讓錯誤終止程序。 對於Web應用程序,異常通常會冒泡到全局異常處理程序,從而終止該請求但讓其他請求繼續進行。 對於單元測試,測試運行程序會捕獲並記錄異常,以便其他測試可以繼續進行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.