概述
第十二章 通过异常处理错误
1、概念
因为异常机制将保证能够捕获这个错误,所以不用小心翼翼的各种去检查。而处理错误只需要在一个地方完成,那就是 异常处理程序。
2、基本异常
异常情形是指阻止当前方法或作用域继续执行的问题。
异常处理程序将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。
在没有其它办法的情况下,异常允许我们强制程序停止运行,并告诉我们出现了什么问题。理想状态下,还可以强制程序处理问题,并返回到稳定状态的。
异常参数:
用new在堆上创建异常对象,所有标准异常类都有两个构造器,一个默认的,一个带参的。
能够抛出任意类型的Throwable对象,它是异常类型的根类。
3、捕获异常
监控区域是一个可能产生异常的代码,并且后面跟着处理这些异常的代码。
如果在方法内部抛出了异常,那么这个方法就此结束。如果不希望这个方法结束,那么可以在方法内设置一个特殊的块来捕获异常,即try块。为什么叫try呢,因为在这个块里“尝试”各种可能产生异常的方法进行调用,所以是try。
try {
// Code that might generate exceptions
} catch(Type1 id1)|{
// Handle exceptions of Type1
} catch(Type2 id2) {
// Handle exceptions of Type2
} catch(Type3 id3) {
// Handle exceptions of Type3
}
异常抛出后,异常处理机制将搜索参数与异常类型相匹配的第一个处理程序,进入catch语句处理,此时认为异常的到了处理。catch子句结束,则处理程序不再往下找匹配了。
终止与恢复:
异常处理理论上有两种基本模型,java支持终止模型。该模型假设错误非常关键,一旦异常被抛出,那么错误已经无可挽回,程序不能继续执行。
另一种模型是恢复模型,就是先修正错误,然后重新进入该方法。这个模型假定了修正完之后再进入执行一定会成功。
相比较终止模型还是比较占优的,因为恢复模型需要了解异常抛出的地点,麻烦。
4、创建自定义异常
public MyException() {}
public MyException(String msg) { super(msg); }
}
System.out.println("Throwing MyException from g()");
throw new MyException("Originated in g()");
}
at FullConstructors.f(FullConstructors.java:11)
at FullConstructors.main(FullConstructors.java:19)
import java.io.*;
class LoggingException extends Exception {
private static Logger logger =
Logger.getLogger("LoggingException");
public LoggingException() {
StringWriter trace = new StringWriter();
printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
}
public class LoggingExceptions {
public static void main(String[] args) {
try {
throw new LoggingException();
} catch(LoggingException e) {
System.err.println("Caught " + e);
}
try {
throw new LoggingException();
System.err.println("Caught " + e);
}
}
} /* Output: (85% match)
Aug 30, 2005 4:02:31 PM LoggingException <init>
SEVERE: LoggingException
at LoggingExceptions.main(LoggingExceptions.java:19)
Caught LoggingException
Aug 30, 2005 4:02:31 PM LoggingException <init>
SEVERE: LoggingException
at LoggingExceptions.main(LoggingExceptions.java:24)
Caught LoggingException
import java.io.*;
public class LoggingExceptions2 {
private static Logger logger =
Logger.getLogger("LoggingExceptions2");
static void logException(Exception e) {
StringWriter trace = new StringWriter();
e.printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch(NullPointerException e) {
logException(e);
}
}
} /* Output: (90% match)
Aug 30, 2005 4:07:54 PM LoggingExceptions2 logException
SEVERE: java.lang.NullPointerException
at LoggingExceptions2.main(LoggingExceptions2.java:16)
5、异常说明
6、捕获所有异常
System.out.println("Caught an exception");
}
Exception可以调用其从基类继承的方法:
String getLocalizedMessage( )
获取详细信息(抛出异常对象所带的参数),或者用本地语言表示的详细信息。
返回对Throwable的简单描述,要是有详细信息的话,也会把它包含在内。
void printStackTrace(PrintStream)
void printStackTrace(java.io.PrintWriter)
用于在Throwable对象的内部记录栈帧的当前状态。
public class ExceptionMethods {
public static void main(String[] args) {
try {
throw new Exception("My Exception");
} catch(Exception e) {
print("Caught Exception");
print("getMessage():" + e.getMessage());
print("getLocalizedMessage():" +
e.getLocalizedMessage());
print("toString():" + e);
print("printStackTrace():");
e.printStackTrace(System.out);
}
}
} /* Output:
Caught Exception
getMessage():My Exception
getLocalizedMessage():My Exception
toString():java.lang.Exception: My Exception
printStackTrace():
java.lang.Exception: My Exception
at ExceptionMethods.main(ExceptionMethods.java:8)
栈轨迹:
static void f() {
// Generate an exception to fill in the stack trace
try {
throw new Exception();
} catch (Exception e) {
for(StackTraceElement ste : e.getStackTrace())
System.out.println(ste.getMethodName());
}
}
static void g() { f(); }
static void h() { g(); }
public static void main(String[] args) {
f();
System.out.println("--------------------------------");
g();
System.out.println("--------------------------------");
h();
}
} /* Output:
f
main
--------------------------------
f
g
main
--------------------------------
f
g
h
main
重新抛出异常
挡在异常处理模块里继续抛出异常,那么printStackTrace()方法显示的将是原来异常抛出点的调用栈信息,而非重新抛出点的的信息。System.out.println("An exception was thrown");
throw e;
}
System.out.println("An exception was thrown");
throw (Exception)e.fillInStackTrace();
}
异常链
在捕获一个异常后抛出另一个异常,并希望把原始异常的信息保存下来,这被称为异常链。Throwable的子类可以在构造器中接受一个case对象作为参数。这个case参数表示原始异常,这样通过把原始异常传递给新的异常。
7、Java标准异常
特例RuntimeException
8、使用finally进行清理
// The guarded region: Dangerous activities
// that might throw A, B, or C
} catch(A a1) {
// Handler for situation A
} catch(B b1) {
// Handler for situation B
} catch(C c1) {
// Handler for situation C
} finally {
// Activities that happen every time
}
甚至当当前异常1还没捕获的情况下,又抛出了个异常2,那么这个异常2的finally也会先执行,再到捕获异常1的程序块中。
class FourException extends Exception {}
public class AlwaysFinally {
public static void main(String[] args) {
print("Entering first try block");
try {
print("Entering second try block");
try {
throw new FourException();
} finally {
print("finally in 2nd try block");
}
} catch(FourException e) {
System.out.println(
"Caught FourException in 1st try block");
} finally {
System.out.println("finally in 1st try block");
}
}
} /* Output:
Entering first try block
Entering second try block
finally in 2nd try block
Caught FourException in 1st try block
finally in 1st try block
当涉及break和continue时,finally子句也会得到执行。
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) {
try {
LostMessage lm = new LostMessage();
try {
lm.f();
} finally {
lm.dispose();
}
} catch(Exception e) {
System.out.println(e);
}
}
} /* Output:
A trivial exception
2、
public static void main(String[] args) {
try {
throw new RuntimeException();
} finally {
// Using ‘return’ inside the finally block
// will silence any thrown exception.
return;
}
}
}
9、异常的限制
当覆盖 方法时,只能抛出在基类方法的异常说明里列出的那些异常。这个限制意味着,当基类代码运用到派生类时,依旧有用。
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.out.println("Pop foul");
} catch(RainedOut e) {
System.out.println("Rained out");
} catch(BaseballException e) {
System.out.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.out.println("Strike");
} catch(Foul e) {
System.out.println("Foul");
} catch(RainedOut e) {
System.out.println("Rained out");
} catch(BaseballException e) {
System.out.println("Generic baseball exception");
}
}
}
当处理派生类对象时,编译器只会强制要求捕获派生类该方法产生的异常。如果向上转型为基类,编译器会要求捕获基类方法产生的异常。很智能的。
异常说明本身并不属于方法类型的范畴中,因此不参与重载的判断。
基于特定方法的“异常说明的接口”不是变大了而是变小了,小于等于基类异常说明表——这恰好和类接口在继承时的情形相反。
10、构造器
好恶心不看
11、异常的匹配
class Sneeze extends Annoyance {}
public class Human {
public static void main(String[] args) {
// Catch the exact type:
try {
throw new Sneeze();
} catch(Sneeze s) {
System.out.println("Caught Sneeze");
} catch(Annoyance a) {
System.out.println("Caught Annoyance");
}
// Catch the base type:
try {
throw new Sneeze();
} catch(Annoyance a) {
System.out.println("Caught Annoyance");
}
}
} /* Output:
Caught Sneeze
Caught Annoyance
12、其它可选方式
最后
以上就是平淡月光为你收集整理的Java编程思想第四版读书笔记——第十二章 通过异常处理错误第十二章 通过异常处理错误的全部内容,希望文章能够帮你解决Java编程思想第四版读书笔记——第十二章 通过异常处理错误第十二章 通过异常处理错误所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复