1.java异常层次结构
在 Java 程序设计语言中,使用一种异常处理的错误捕获机制。当程序运行过程中发生一些异常情况,程序有可能被中断、或导致错误的结果出现。
在这种情况下,程序不会返回任何值,而是抛出封装了错误信息的对象。
异常分为两大类,程序员只能抛出Exception异常对象,Error对象是Java系统在内部发生错误或者资源耗尽时才抛出的。
其中,BussinessException 属于基本业务操作异常,所有业务操作异常都继承于该类。例如,通常 UI 层或 Web 层是由系统最终用户执行业务操作驱动,因此最好抛出业务类异常。ServiceException 一般属于中间服务层异常,该层操作引起的异常一般包装成基本 ServiceException。DAOException 属于数据访问相关的基本异常。
对于多层系统,每一层都有该层的基本异常。在层与层之间的信息传递与方法调用时候,一旦在某层发生异常,传递到上一层的时候,一般包装成该层异常,直至与用户最接近的 UI 层,从而转化成用户友好的错误信息。
异常转译就是将一种异常转换为另一种异常。异常转译针对所有继承 Throwable 超类的异常类而言的。如下图 7 中代码所示展示了异常转译的一个例子:
图 7. 异常转译代码样例
2.java异常处理的分类
2.1)可检测异常
可检测异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,例如:sqlExecption 这个异常就是一个检测异常。你连接 JDBC 时,不捕捉这个异常,编译器就通不过,不允许编译。
2.2)非检测异常
有两个主要类定义非检测异常:RuntimeException 和 Error。
非检测异常不遵循处理或声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已解决了这样一个异常。例如:一个数组为 3 个长度,当你使用下标为3时,就会产生数组下标越界异常。这个异常 JVM 不会进行检测,要靠程序员来判断。Error 子类属于非检测异常,因为无法预知它们的产生时间。若 Java 应用程序内存不足,则随时可能出现 OutOfMemoryError;起因一般不是应用程序的特殊调用,而是 JVM 自身的问题。另外,Error 一般表示应用程序无法解决的严重问题。RuntimeException 类也属于非检测异常,因为普通 JVM 操作引发的运行时异常随时可能发生,此类异常一般是由特定操作引发。但这些操作在 Java 应用程序中会频繁出现。因此,它们不受编译器检查与处理或声明规则的限制。
3.Java 异常的处理
在 Java 应用程序中,对异常的处理有两种方式:处理异常和声明异常。
3.1)处理异常:try、catch 和 finally
若要捕获异常,则必须在代码中添加异常处理器块。这种 Java 结构可能包含 3 个部分,都有 Java 关键字。下面的例子中使用了 try-catch-finally 代码结构。
1 import java.io.*; 2 public class EchoInputTryCatchFinally { 3 public static void main(String args[]){ 4 System.out.println("Enter text to echo:"); 5 InputStreamReader isr = new InputStreamReader(System.in); 6 BufferedReader inputReader = new BufferedReader(isr); 7 try{ 8 String inputLine = inputReader.readLine(); 9 System.out.println("Read:" + inputLine); 10 } 11 catch(IOException exc){ 12 System.out.println("Exception encountered: " + exc); 13 } 14 finally{ 15 System.out.println("End. "); 16 } 17 } 18}
其中:
- try 块:将一个或者多个语句放入 try 时,则表示这些语句可能抛出异常。编译器知道可能要发生异常,于是用一个特殊结构评估块内所有语句。
- catch 块:当问题出现时,一种选择是定义代码块来处理问题,catch 块的目的便在于此。catch 块是 try 块所产生异常的接收者。基本原理是:一旦生成异常,则 try 块的执行中止,JVM 将查找相应的 JVM。
- finally 块:还可以定义 finally 块,无论运行 try 块代码的结果如何,该块里面的代码一定运行。在常见的所有环境中,finally 块都将运行。无论 try 块是否运行完,无论是否产生异常,也无论是否在 catch 块中得到处理,finally 块都将执行。
try-catch-finally 规则:
- 必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。
- 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
- catch 块与相应的异常类的类型相关。
- 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。
- 可嵌套 try-catch-finally 结构。
- 在 try-catch-finally 结构中,可重新抛出异常。
- 除了下列情况,总将执行 finally 做为结束:JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击
3.2)声明异常
若要声明异常,则必须将其添加到方法签名块的结束位置。下面是一个实例:
public void errorProneMethod(int input) throws java.io.IOException { //Code for the method,including one or more method //calls that may produce an IOException }
这样,声明的异常将传给方法调用者,而且也通知了编译器:该方法的任何调用者必须遵守处理或声明规则。声明异常的规则如下:
- 必须声明方法可抛出的任何可检测异常(checked exception)。
- 非检测性异常(unchecked exception)不是必须的,可声明,也可不声明。
- 调用方法必须遵循任何可检测异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。
4.java异常处理注意事项
1、重写的方法不能抛出与被重写的方法不同的异常。
2、Catch语句块中异常的父类不能放在最前面。子类应该放在最前面。
例如:catch(Exception e){
}catch(IOException e){
}错误,因为父类Exception 已经捕获,所以IOException会报错。
我们应该这样写:
catch(IOException e){
}catch(Exception e){
}
3、抛出什么类型的异常(为可恢复的条件使用检查型异常,为编程错误使用运行时异常)
当抛出异常时,如果希望调用者能够拦截并且恢复程序的执行,应该抛出checked exception(即可恢复情况使用checked exception)。为了让调用者能够恢复程序的执行,checked exception对象往往需要提供一些方法使得调用者可以获得一些有助于恢复的信息。所以,换位思考是个好主意,想一想如果调用者拦截了你抛出的异常,他能够恢复程序的执行,你就应该抛出checked exception,否则你就应该抛出RuntimeException.
-
1 try{ 2 // Error-prone code 3 } 4 catch(IOException e){ 5 String msg = "If you didn ’ t have a problem before,you do now!"; 6 throw new Exception(msg); 7 }
因为没有原始异常的信息,所以处理器块无法确定问题的起因,也不知道如何更正问题。
6、throw和throws的区别
throws是用来声明一个方法可能抛出的所有异常信息
throw则是指抛出的一个具体的异常类型。 通常在一个方法(类)的声明处通过throws声明方法(类)可能抛出的异常信息,而在方法(类)内部通过throw声明一个具体的异常信息。 throws通常不用显式的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw则需要用户自己捕获相关的异常,而后在对其进行相关包装,最后在将包装后的异常信息抛
两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。
另:throw还可以有相当于return的作用,终止程序!
7、自定义异常
TestMyException.java继承Exception,构造方法调用父类方法存储错误信息
public class TestMyException extends Exception{ /** * 自定义异常 */ private static final long serialVersionUID = 1L; public TestMyException(String message){//构造器记录错误信息异常exception.getMessage; super(message); } public TestMyException(Throwable t){//异常类的父类,泛型 super(t); } public TestMyException(Throwable t , String message){ super(message,t); } }
public static void test() throws TestMyException{
int x = 0;
if(x == 0){
throw new TestMyException("除数不能为0");
}
}
/**
* @param args
*/
public static void main(String[] args){
try {
test();
} catch (TestMyException e) {
System.out.println(e.getMessage());
}
}
}
参考链接:
1、http://www.oschina.net/translate/10-java-exception-and-error-interview-questions-answers-programming
2、http://www.ibm.com/developerworks/cn/java/j-lo-exception-misdirection/
3、http://www.ibm.com/developerworks/cn/java/j-jtp05254/
4、http://www.ibm.com/developerworks/cn/java/j-lo-exceptionframework/
补充一个经典链接:http://blog.csdn.net/hguisu/article/details/6155636
主要搞定这两个demo的区别:
demo1:
package exception; public class TestException { public TestException() { } //一般不在finally return值 boolean testEx() throws Exception { boolean ret = true; try { ret = testEx1(); } catch (Exception e) { System.out.println("testEx, catch exception"); ret = false; throw e; } finally { System.out.println("testEx, finally; return value=" + ret); } return ret; } boolean testEx1() throws Exception { boolean ret = true; try { ret = testEx2(); if (!ret) { return false; } System.out.println("testEx1, at the end of try"); return ret; } catch (Exception e) { System.out.println("testEx1, catch exception"); ret = false; throw e; } finally { System.out.println("testEx1, finally; return value=" + ret); /*return ret; */ } } boolean testEx2() throws Exception { boolean ret = true; try { int b = 12; int c; for (int i = 2; i >= -2; i--) { c = b / i; System.out.println("i=" + i); } return true; } catch (Exception e) { System.out.println("testEx2, catch exception"); ret = false; throw e; //抛出异常,但跑到finally有return值,调用者方法的方法者(即textEx1)会直接忽略异常 } finally { System.out.println("testEx2, finally; return value=" + ret); /*return ret; */ } } public static void main(String[] args) { TestException testException1 = new TestException(); try { testException1.testEx(); } catch (Exception e) { e.printStackTrace(); } } }
demo1输出:
i=2 i=1 java.lang.ArithmeticException: / by zero testEx2, catch exception testEx2, finally; return value=false testEx1, catch exception testEx1, finally; return value=false testEx, catch exception testEx, finally; return value=false at exception.TestException.testEx2(TestException.java:46) at exception.TestException.testEx1(TestException.java:24) at exception.TestException.testEx(TestException.java:10) at exception.TestException.main(TestException.java:63)
demo2:
package exception; public class TestException { public TestException() { } //一般不再finally return值 boolean testEx() throws Exception { boolean ret = true; try { ret = testEx1(); } catch (Exception e) { System.out.println("testEx, catch exception"); ret = false; throw e; } finally { System.out.println("testEx, finally; return value=" + ret); return ret; } } boolean testEx1() throws Exception { boolean ret = true; try { ret = testEx2(); if (!ret) { return false; } System.out.println("testEx1, at the end of try"); return ret; } catch (Exception e) { System.out.println("testEx1, catch exception"); ret = false; throw e; } finally { System.out.println("testEx1, finally; return value=" + ret); return ret; } } boolean testEx2() throws Exception { boolean ret = true; try { int b = 12; int c; for (int i = 2; i >= -2; i--) { c = b / i; System.out.println("i=" + i); } return true; } catch (Exception e) { System.out.println("testEx2, catch exception"); ret = false; throw e; //抛出异常,但跑到finally有return值,调用者方法的方法者(即textEx1)会直接忽略异常 } finally { System.out.println("testEx2, finally; return value=" + ret); return ret; } } public static void main(String[] args) { TestException testException1 = new TestException(); try { testException1.testEx(); } catch (Exception e) { e.printStackTrace(); } } }
demo2输出:
i=2 i=1 testEx2, catch exception testEx2, finally; return value=false testEx1, finally; return value=false testEx, finally; return value=false
相关推荐
深入理解java异常处理机制,很详细的,去了,你们的!
关于异常的定义和理解,各类异常的区分.等等
JDK1.7以上的异常体系,需要后续的不断总结和完善,学习jdk必备!
深入理解java异常(异常中的Error+异常中的Exception+检查异常+运行时异常+异常处理+throws关键字等)
理解异常的基础操作以及最简单的捕获处理 理解多异常捕获处理 理解声明抛出异常 掌握自定义异常 掌握异常处理注意事项 第1章 异常 什么是异常?Java代码在运行时期发生的问题就是异常。 在Java中,把异常信息封装成...
一、异常处理的理解? 异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。 因此处理这种错误,就称为异常处理。 二、异常处理如何操作? C# 异常处理时建立在四个关键词之上的:try、...
C#异常处理分析,简单易懂,例子详细,非常不错,希望对大家有用
或许从第一次使用异常开始,我们就要经常考虑诸如何时捕获异常,何时抛出异常,异常的性能如何之类的问题,有时还想了解究竟什么是异常,它的机制又是什么。本文试着对这些问题进行讨论。
里面讲述了 java 异常体系,简介,及流程,可以让你对异常更加理解
对java异常的工作过程进行详细解释,让初学者更好的掌握异常处理机制
俺花了N个大洋买来的,现在免费提供给大家
深入理解linux内核 中文版 第三版 第4章 中断和异常.pdf
深入理解java异常处理机制Java开发Java经验技巧共19页.pdf.zip
深入理解JVM内存区域与内存溢出异常
概念与实例相结合 让理解异常不再那么困难 适合新人阅读
深入理解Java异常体系Java系列2021.pdf
全面描述linux arm缺页异常的处理原理和处理方式,结合原理的解释描述以及全部相关的源码注释,深刻理解缺页异常
深刻理解 java 语言中独特的异常处理机制,掌握处理问题的方法。异常处理是java语言中一个独特之处,主要使用捕获异常和声明抛弃异常两种方法来处理程序中可能出现异常的语句块。
鉴于手性异常在粒子物理学以外的各个领域的最新应用,我们讨论了手性异常的一些基本方面,这可能有助于加深我们对粒子物理学中对手性异常的理解。 首先表明,Weyl模型H =vFσ→·p→(t)的Berry相(及其推广)在...
ARM支持7种异常。问题时发生了异常后ARM是如何响应的呢?下面一起来学习一下