這是三個問題,但這不是第一次發生在這裏。 :-)
是的,你必須處理它們或聲明它們,因爲它們是檢查異常。你必須這麼做的原因是,調用你的代碼的代碼知道你的代碼可能失敗的方式(因爲你聲明瞭它可以拋出的異常)。
這段代碼非常簡單,所以分離和收益並不是那麼明顯。但考慮打開兩個流,使用轉換代碼(包括調用從屬方法)從一個到另一個進行復制。最終你會得到一個有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和寫OPS等
如果你有興趣,這裏是一個完整的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();
}
}
這是三個不同的問題,而不是* a *問題。 –
#1中的問題是什麼?是的,你必須處理它們或宣佈它們。 –
關於Q2,假設'result'被用作業務邏輯中的一個關鍵值,那麼只有當你的代碼是一個有效變量的時候,你纔想把'result'賦給你的代碼,在'try'塊中如果沒有拋出異常,則使用'result'。如果拋出異常,你可以在'catch'塊中給'result'一個默認值。因此,您的業務邏輯代碼從不受由於result變量引發的異常的影響。 – OPK