RuntimeException異常以及其子類異常,不需要異常說明就可以從任何地方拋出
是uncheck exception。

從程序的輸出看出,無論有沒有拋出異常,finally子句總會得到執行,
這個程序也啟發我們應該如何處理我們前面講到過的,Java異常(和C++
的異常一樣)會阻止程序回到異常拋出的地方恢復執行這個問題。
如果你把try塊放進一個循環,你就能構建一個程序運行之前必須滿足的條件。


class ThreeException extends Exception
{
}

public class FinallyWorks
{

static int count = 0;

public static void main(String[] args)
{

while(true)
{

try
{

if(count++==0)
{
throw new ThreeException();
}
System.out.println("No Exception");

}catch(Exception e)
{
System.err.println("ThreeException");

}finally
{
System.err.println("In finally clause");
if(count==2)
break;
}
}
}

}

ThreeException
In finally clause
No Exception
In finally clause





Finally子句的執行

class FourException extends Exception
{
}


public class AlwaysFinally
{


public static void main(String[] args)
{
System.out.println("Entering first try block");

try
{
System.out.println("Entering second try block");

try
{
throw new FourException();

} finally
{
System.out.println("finally in 2nd try block");
}

} catch (FourException e)
{
System.err.println("Caught FourException in 1st try block");

} finally
{
System.err.println("finally in 1st try block");
}

}
}
Entering first try block
Entering second try block
finally in 2nd try block
Caught FourException in 1st try block
finally in 1st try block





丟失的異常
package exceptiontest;


class VeryImportantException extends Exception
{

public String toString()
{
return "A very important exception!";
}
}


class HoHumException extends Exception
{

public String toString()
{
return "A trivial exception";
}
}


public class LostMessage
{

void f() throws VeryImportantException
{
throw new VeryImportantException();
}


void dispose() throws HoHumException
{
throw new HoHumException();
}


public static void main(String[] args) throws Exception
{
LostMessage lm = new LostMessage();

try
{
lm.f();

} finally
{
lm.dispose();
}

}
}

看到了嗎?VeryImportantException消失的無影無蹤了,它直接被finally里面的HoHumException給取代了,這是一個相當嚴重的錯誤,它表示這個異常被徹底丟失了,而在真實環境中,這種情況會遠比上述程序更為微妙,更難以察覺。相反,C++會把這種“第一個異常尚未得到處理,就產生了第二個異常”的現象,當成極端嚴重的編程錯誤。







//Java構造函數中發生的異常

class InputFile
{
private BufferedReader in;


public InputFile(String fname) throws Exception
{

try
{
in = new BufferedReader(new FileReader(fname));
// Other code that might throw exceptions

} catch (FileNotFoundException e)
{
System.err.println("Could not open " + fname);
// Wasn't open, so don't close it
throw e;

} catch (Exception e)
{
// All other exceptions must close it

try
{
in.close();

} catch (IOException e2)
{
System.err.println("in.close() unsuccessful");
}
throw e; // Rethrow

} finally
{
// Don't close it here!!!
}
}


public String getLine()
{
String s;

try
{
s = in.readLine();

} catch (IOException e)
{
throw new RuntimeException("readLine() failed");
}
return s;
}


public void dispose()
{

try
{
in.close();
System.out.println("dispose() successful");

} catch (IOException e2)
{
throw new RuntimeException("in.close() failed");
}
}
}


public class Cleanup
{
private static Test monitor = new Test();


public static void main(String[] args)
{

try
{
InputFile in = new InputFile("Cleanup.java");
String s;
int i = 1;
while ((s = in.getLine()) != null)
; // Perform line-by-line processing here
in.dispose();

} catch (Exception e)
{
System.err.println("Caught Exception in main");
e.printStackTrace();
}

monitor.expect(new String[]
{ "dispose() successful" });
}
} // /:~



異常處理系統還是一扇能讓你放棄程序正常運行順序的暗門。當某種“異常情況”出現的時候,這個門就開啟了,于是程序再也不能,或者再也不按照正常的順序執行下去。異常表示的是一些“當前方法無法處理”的情況。之所以要開發異常處理系統,是因為要對每次函數調用的每個錯誤做檢查實在是太費力了,所以程序員根本就不去做。結果就是把錯誤給忽略了。
異常處理的一個重要準則就是“如果你不知道該如何處理這個異常,你就別去捕捉它”。實際上,異常處理有一項重要的目標,這就是將處理異常的代碼從異常發生的地方移開。這樣你就能在一個地方集中精力去解決你想解決的問題,然后再到另外一個地方處理這些異常問題了。
但是 java所特有的checked exception將這種情況變的稍微復雜些了,這是因為即使你不準備這么做,編譯器也強制要求你在try的后面加上catch子句,于是這就導致了“錯誤地私吞harmful if swallowed”的問題了:
注意一下throw e.fillInStackTrace();的用法
package exceptiontest;

import java.util.Collections;


public class Rethrowing
{

public static void f()throws Exception
{
System.err.println("originating the exception n f()");
throw new Exception("throw from f()");
}

public static void g()throws Throwable
{

try
{
f();

}catch(Exception e)
{
System.err.println("Inside g(),e.printlStackTrace()");
e.printStackTrace();
//throw e;
throw e.fillInStackTrace();
}
}

public static void h()throws Exception
{
f();
}

public static void main(String[] args)throws Throwable
{

try
{
g();

}catch(Exception e)
{
System.err.println("Caught in main,e.printStackTrace");
e.printStackTrace();
}
}

}

運行結果:
originating the exception n f()
Inside g(),e.printlStackTrace()
java.lang.Exception: throw from f()
at exceptiontest.Rethrowing.f(Rethrowing.java:8)
at exceptiontest.Rethrowing.g(Rethrowing.java:12)
at exceptiontest.Rethrowing.main(Rethrowing.java:26)
Caught in main,e.printStackTrace
java.lang.Exception: throw from f()
at exceptiontest.Rethrowing.g(Rethrowing.java:17)
at exceptiontest.Rethrowing.main(Rethrowing.java:26)
如不使用
throw e.fillInStackTrace(),而是throw e
originating the exception n f()
Inside g(),e.printlStackTrace()
java.lang.Exception: throw from f()
at exceptiontest.Rethrowing.f(Rethrowing.java:8)
at exceptiontest.Rethrowing.g(Rethrowing.java:12)
at exceptiontest.Rethrowing.main(Rethrowing.java:26)
Caught in main,e.printStackTrace
java.lang.Exception: throw from f()
at exceptiontest.Rethrowing.f(Rethrowing.java:8)
at exceptiontest.Rethrowing.g(Rethrowing.java:12)
at exceptiontest.Rethrowing.main(Rethrowing.java:26)
Exception chaining
Often you want to catch one exception and throw another, but still keep the information about the originating exception—this is called exception chaining. Prior to JDK 1.4, programmers had to write their own code to preserve the original exception information, but now all Throwable subclasses may take a cause object in their constructor. The cause is intended to be the originating exception, and by passing it in you maintain the stack trace back to its origin, even though you’re creating and throwing a new exception at this point.
It’s interesting to note that the only Throwable subclasses that provide the cause argument in the constructor are the three fundamental exception classes Error (used by the JVM to report system errors), Exception, and RuntimeException. If you want to chain any other exception types, you do it through the initCause( ) method rather than the constructor.
//: c09:DynamicFields.java
// A Class that dynamically adds fields to itself.
// Demonstrates exception chaining.
// {ThrowsException}
import com.bruceeckel.simpletest.*;


class DynamicFieldsException extends Exception
{}


public class DynamicFields
{
private static Test monitor = new Test();
private Object[][] fields;

public DynamicFields(int initialSize)
{
fields = new Object[initialSize][2];
for(int i = 0; i < initialSize; i++)

fields[i] = new Object[]
{ null, null };
}

public String toString()
{
StringBuffer result = new StringBuffer();

for(int i = 0; i < fields.length; i++)
{
result.append(fields[i][0]);
result.append(": ");
result.append(fields[i][1]);
result.append("\n");
}
return result.toString();
}

private int hasField(String id)
{
for(int i = 0; i < fields.length; i++)
if(id.equals(fields[i][0]))
return i;
return -1;
}
private int

getFieldNumber(String id) throws NoSuchFieldException
{
int fieldNum = hasField(id);
if(fieldNum == -1)
throw new NoSuchFieldException();
return fieldNum;
}

private int makeField(String id)
{
for(int i = 0; i < fields.length; i++)

if(fields[i][0] == null)
{
fields[i][0] = id;
return i;
}
// No empty fields. Add one:
Object[][]tmp = new Object[fields.length + 1][2];
for(int i = 0; i < fields.length; i++)
tmp[i] = fields[i];
for(int i = fields.length; i < tmp.length; i++)

tmp[i] = new Object[]
{ null, null };
fields = tmp;
// Reursive call with expanded fields:
return makeField(id);
}
public Object

getField(String id) throws NoSuchFieldException
{
return fields[getFieldNumber(id)][1];
}
public Object setField(String id, Object value)

throws DynamicFieldsException
{

if(value == null)
{
// Most exceptions don't have a "cause" constructor.
// In these cases you must use initCause(),
// available in all Throwable subclasses.
DynamicFieldsException dfe =
new DynamicFieldsException();
dfe.initCause(new NullPointerException());
throw dfe;
}
int fieldNumber = hasField(id);
if(fieldNumber == -1)
fieldNumber = makeField(id);
Object result = null;

try
{
result = getField(id); // Get old value

} catch(NoSuchFieldException e)
{
// Use constructor that takes "cause":
throw new RuntimeException(e);
}
fields[fieldNumber][1] = value;
return result;
}

public static void main(String[] args)
{
DynamicFields df = new DynamicFields(3);
System.out.println(df);

try
{
df.setField("d", "A value for d");
df.setField("number", new Integer(47));
df.setField("number2", new Integer(48));
System.out.println(df);
df.setField("d", "A new value for d");
df.setField("number3", new Integer(11));
System.out.println(df);
System.out.println(df.getField("d"));
Object field = df.getField("a3"); // Exception

} catch(NoSuchFieldException e)
{
throw new RuntimeException(e);

} catch(DynamicFieldsException e)
{
throw new RuntimeException(e);
}

monitor.expect(new String[]
{
"null: null",
"null: null",
"null: null",
"",
"d: A value for d",
"number: 47",
"number2: 48",
"",
"d: A new value for d",
"number: 47",
"number2: 48",
"number3: 11",
"",
"A value for d",
"Exception in thread \"main\" " +
"java.lang.RuntimeException: " +
"java.lang.NoSuchFieldException",
"\tat DynamicFields.main(DynamicFields.java:98)",
"Caused by: java.lang.NoSuchFieldException",
"\tat DynamicFields.getFieldNumber(" +
"DynamicFields.java:37)",
"\tat DynamicFields.getField(DynamicFields.java:58)",
"\tat DynamicFields.main(DynamicFields.java:96)"
});
}
} ///:~




方法覆蓋時異常的情況
package exceptiontest;
//方法覆蓋時異常的情況
//: c09:StormyInning.java
//Overridden methods may throw only the exceptions
//specified in their base-class versions, or exceptions
//derived from the base-class exceptions.


class BaseballException extends Exception
{
}


class Foul extends BaseballException
{
}


class Strike extends BaseballException
{
}


abstract class Inning
{

public Inning() throws BaseballException
{
}


public void event() throws BaseballException
{
// Doesn't actually have to throw anything
}

public abstract void atBat() throws Strike, Foul;


public void walk()
{
} // Throws no checked exceptions
}


class StormException extends Exception
{
}


class RainedOut extends StormException
{
}


class PopFoul extends Foul
{
}


interface Storm
{
public void event() throws RainedOut;

public void rainHard() throws RainedOut;
}


public class StormyInning extends Inning implements Storm
{
// OK to add new exceptions for constructors, but you
// must deal with the base constructor exceptions:
//構造函數可以多,但是它必須加基類構造函數所聲明的異常

public StormyInning() throws RainedOut, BaseballException
{
}


public StormyInning(String s) throws Foul, BaseballException
{
}

// Regular methods must conform to base class:
//異常聲明只少不多,但這種異常方面的限制對構造函數不起作用
// ! void walk() throws PopFoul {} //Compile error
// Interface CANNOT add exceptions to existing
// methods from the base class:以基類為準而不是以接口為準
// ! public void event() throws RainedOut {}
// If the method doesn't already exist in the
// base class, the exception is OK:

public void rainHard() throws RainedOut
{
}

// You can choose to not throw any exceptions,
// even if the base version does:
//異常聲明只少不多*****************************

public void event()
{
}

// Overridden methods can throw inherited exceptions:

public void atBat() throws PopFoul
{
}


public static void main(String[] args)
{

try
{
StormyInning si = new StormyInning();
si.atBat();

} catch (PopFoul e)
{
System.err.println("Pop foul");

}catch(Foul e)
{

}catch (RainedOut e)
{
System.err.println("Rained out");

} catch (BaseballException e)
{
System.err.println("Generic baseball exception");
}
// Strike not thrown in derived version.

try
{
// What happens if you upcast?
Inning i = new StormyInning();
i.atBat();
// You must catch the exceptions from the
// base-class version of the method:

} catch (Strike e)
{
System.err.println("Strike");

} catch (Foul e)
{
System.err.println("Foul");

} catch (RainedOut e)
{
System.err.println("Rained out");

} catch (BaseballException e)
{
System.err.println("Generic baseball exception");
}
}
}

posted on 2009-06-18 23:40
Frank_Fang 閱讀(1007)
評論(0) 編輯 收藏 所屬分類:
Java編程