异常处理

2016-03-01 17:55:27   最后更新: 2016-03-01 17:55:27   访问数量:542




基本的语法错误会在编译期被编译器报告出来,但是更多的情况是在运行时由于种种原因导致的异常情况

很多情况下,发现异常情况者不知道该如何去解决这个异常情况,因此他需要抛出异常由其他部分去解决,java 提供的异常处理机制就是这样的一个抽象

异常处理是 java 中唯一正式的错误报告机制,并且编译器强制执行了异常处理机制

 

当代码执行过程中遇到了异常情况,如果当前环境无法处理,就要跑出去让外层处理

抛出异常后,java 首先在堆上创建一个异常对象,然后中止当前的执行,弹出一场对象的引用,此时,异常处理机制接管程序,开始寻找下一步恰当的执行代码,也就是寻找异常处理程序,以便于程序从异常状态中恢复

 

下面的代码展示了一个简单的异常处理流程:

package com.techlog.test; public class Test { public static void main(String[] argv) { Test test = new Test(); test.getException(); } private void getException() { try { throwException(); } catch (NullPointerException e) { System.out.println("catch exception"); } } private void throwException() { System.out.println("ready to throw exception"); Integer i = null; if (i == null) { throw new NullPointerException(); } System.out.println("after throw exception"); } }

 

程序输出:

ready to throw exception

catch exception

 

如上面的例子,使用 throw 关键字可以创建并抛出一个异常,在合适的外层位置,通过 try 块监控异常的抛出,并通过 catch 块捕获和处理异常:

try { // Code that might generate exceptions } catch(Type1 id1) { // Handle exception of Type1 } catch(Type2 id2) { // Handle exception of Type2 } finally { // Always }

 

catch 块可以有任意多个,与 switch case 语句非常类似,jvm 会根据抛出的异常类型自动匹配到对应的 catch 块执行,但 jvm 是按照代码的书写顺序查找的,一旦找到匹配块,不会继续查找,同时,jvm 并不要求完全匹配,异常类的派生类也会被匹配到基类的处理块中

无论异常是否被抛出,是否被捕获,finally 块总是会被执行

 

java 中通过派生产生了一系列用于被抛出的异常类,如下图所示:

 

 

java 的所有异常类都派生自 Throwable 类,他指定了代码中可用异常传播机制传输的问题的共性,通常分为两类:

派生自他的类有两个,分别是异常 Exception 类和错误 Error 类

 

Error

Error 类表示程序无法处理的错误,一般是运行引用程序中较为严重的问题,大多数错误与代码编写的操作无关,通常是 JVM 运行时出现的问题,此时 JVM 通常会中止线程执行

应用程序无法控制和处理这些错误,而这些错误通常也是不允许出现的情况

 

Exception

Exception 类定义了程序执行过程中,某些操作带来的异常情况

实际的应用代码中可以抛出 Exception,但不能抛出 Error,可以通过捕获机制处理相应的异常,也可以自己继承并创建合适的异常类用于抛出

RuntimeException 是一类特殊的 Exception,他不要求程序一定要检查并处理,除此之外的 Exception 则由编译器强制要求了 throws、throw、try、catch 等部分

 

上面的例子中我们使用了 Exception 类的最基本用法

除此之外,java 还为 Exception 提供了很多方法,如支持一个 String 参数的构造器,可以允许你为抛出的异常添加额外的信息

package com.techlog.test; class OwnerException extends Exception { public OwnerException() {} public OwnerException(String s) { super(s); } } public class Test { public static void f() throws OwnerException { System.out.println("Throwing OwnerException from f()"); throw new OwnerException(); } public static void g() throws OwnerException { System.out.println("Throwing OwnerException from g()"); throw new OwnerException("Originated in g()"); } public static void main(String[] argv) { try { f(); } catch (OwnerException e) { e.printStackTrace(System.out); } try { g(); } catch (OwnerException e) { e.printStackTrace(System.out); } } }

 

 

程序输出了:

Throwing OwnerException from f() com.techlog.test.OwnerException at com.techlog.test.Test.f(Test.java:13) at com.techlog.test.Test.main(Test.java:21) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) Throwing OwnerException from g() com.techlog.test.OwnerException: Originated in g() at com.techlog.test.Test.g(Test.java:17) at com.techlog.test.Test.main(Test.java:26) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

 

 

上面的程序展示了使用 printStackTrace 方法获取异常发生时的栈轨迹,参数是输出的流,无参数的重载版本是输出到标准错误流

也可以使用 getStackTrace 方法获取栈轨迹,他返回一个由栈轨迹中的元素所构成的数组,其中每个元素表示一个栈帧,由元素 0 开始自栈顶向下

 






技术帖      龙潭书斋      java      exception      thinking in java      java编程思想      error      异常      try      throw      throws      catch      finally      runtimeexception     


京ICP备15018585号