异常是软件系统不可避免的的问题,软件系统在运行中难免发生不可预知的错误,为了避免异常造成软件自动停止运行造成损失,软件开发语言一般提供异常处理机制。
在Java中定义了两种程序运行发生的错误,它们是Error和Exception,它们都继承自Throwable类。从设计上来讲Error代表的是不能有程序自己处理的异常,比如内存溢出等。
Exception代表的是检查异常,即再编程时必须显示处理的异常,要么try-catch,要么抛出方法外,这是在编译器检查的。
区别于Exception,它的子类RuntimeException是运行时异常(非检查),即不是必需写代码处理它,也可以编译通过。
抛出一个异常;
throw new Throwable("Throwable");
throw new Error("error");
throw new Exception("Exception");
throw new RuntimeException("RuntimeException");
在throw 一个异常之后,throw 语句后面的代码不会再运行,立即退出try{}块或者方法(没被try包裹时,方法不会有返回值,而是把异常沿着函数栈往上抛出,直到被处理)。
指定方法抛出异常
public void method() throws Exception {
throw new Exception("exception by method");
}
异常的处理。可以使用try-catch-finally结构来处理异常,如
try {
HelloWorld helloWorld = new HelloWorld();
helloWorld.method(); //这里会抛出异常
} catch (Throwable t) {
System.out.println(t.getMessage());
}finally {
System.out.println("finally");
}
在上面的代码中,try表示监控异常代码,catch块是处理异常的代码,在发生异常时才执行。finally 不管异常有没有发生都会在try和catch之后执行。
其中try可以指定多个异常,也可以对不同的异常分别处理
try {
HelloWorld helloWorld = new HelloWorld();
helloWorld.method();
} catch (RuntimeException | Error e) { //处理多种异常
System.out.println(e.getMessage());
}catch (Exception e1){ //单独处理Exception 的情况
System.out.println(e1.getMessage());
}
finally {
System.out.println("finally");
}
比较值得注意的是当try块或者catch块中有return语句的情况下,代码的执行过程,下面以实例说明
public static void main(String[] args) {
System.out.println(testEx());
}
public static String testEx() {
try {
method();
return "try";
} catch (Exception e) {
return "catch";
} finally {
return "finally";
}
}
public static void method() {
throw new RuntimeException("exception by method");
}
输出结果为
finally
这里要注意的是,即使在try块或者catch块 有return语句,finally 块还是会执行,这时之前的return结果是被缓存着的。如果finally 中有return语句,那么直接return finally 中的结果。
自定义异常:
虽然Java提供了足够多的异常类型,但是自定义异常在业务当中是非常常见的。一般的,我们会实现继承自Exception,RuntimeException的类型,它们和它们的父类有着一样的特性。
异常抑制:
之前提到finally 中的return会替代try catch块中的return。其实finally 中抛出的异常也会抑制后两者抛出的异常,在调用者那里捕获的是finally 的异常,try catch块中的异常好像消失了。
public static void main(String[] args) {
try {
testEx();
}catch (Exception e){
e.printStackTrace();
}
}
public static String testEx() {
Exception ex = null;
try {
throw new RuntimeException("ex in try");
} catch (Exception e) {
ex = e;
} finally {
RuntimeException runtimeException = new RuntimeException("ex in finally");
runtimeException.addSuppressed(ex); //添加被抑制的异常
throw runtimeException;
}
}
观察输出:
java.lang.RuntimeException: ex in finally
at helloworld.HelloWorld.testEx(HelloWorld.java:27)
at helloworld.HelloWorld.main(HelloWorld.java:14)
Suppressed: java.lang.RuntimeException: ex in try
at helloworld.HelloWorld.testEx(HelloWorld.java:23)
... 1 more
可以发现,mian方法捕捉到的异常是finally产生的,这里我们可以把被抑制的异常手动添加,这样不会丢失有价值的异常信息。
Java7新特性 try with resource
当使用需要关闭的一些资源,比如FileStream这些流,往往要在使用完成之后关闭它,一般的实践是在finally 块中将它们关闭,但是这样会导致代码量相对增多。Java7提供了 try with resource的写法,Java会自动帮我们关闭这些资源,即会自动调用对象的close()方法。
一个 try-with-resources 语句可以像普通的 try 语句那样有 catch 和 finally 块。在try-with-resources 语句中,任意的 catch 或者 finally 块都是在声明的资源被关闭以后才运行。
网友评论