异常处理

使用Java异常处理机制:

把可能会发生错误的代码放进try语句块中。

当程序检测到出现了一个错误时会抛出一个异常对象。

异常处理代码会捕获并处理这个错误。

catch语句块中的代码用于处理错误。

当异常发生时,程序控制流程由try语句块跳转到catch语句块。

不管是否有异常发生,finally语句块中的语句始终保证被执行。

如果没有提供合适的异常处理代码,JVM将会结束掉整个应用程序。

异常分类:

Throwable类有两个直接子类:

Exception:出现的问题是可以被捕获的;

Error:系统错误,通常由JVM处理。

可捕获的异常又可以分为两类:

(1)Check异常:直接派生自Exception的异常类,必须被捕获或再次声明抛出

(2)Runtime异常:派生自RuntimeException的异常类。使用throw语句可以随时抛出这种异常对象: throw new ArithmeticException(…);

JDK1.4 以上提供了assert语句,允许程序在运行期间判断某个条件是否满足,不满足时,抛出AssertionError,例如:

异常的“多态”特性

可以有多个catch语句块,每个代码块捕获一种异常。在某个try块后有两个不同的catch 块捕获两个相同类型的异常是语法错误。

使用catch语句,只能捕获Exception类及其子类的对象。因此,一个捕获Exception对象的catch语句块可以捕获所有“可捕获”的异常。

将catch(Exception e)放在别的catch块前面会使这些catch块都不执行,因为Java不会编译这些catch块。

“finally”的功用

资源泄露:当一个资源不再被某应用程序使用,但此程序并未向系统声明不再使用此资源时发生这种情况

finally语句块主要用于解决资源泄露问题,它位于catch语句块之后,JVM保证它们一定执行。

注意:finally语句块中也可能发生异常,如果这种情况发生,先前的异常被放弃。

动手动脑:多层的异常捕获

比较两个代码的区别:

CatchWho1.java

 public class CatchWho {
public static void main(String[] args) {
try {
try {
throw new ArrayIndexOutOfBoundsException();
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println( "ArrayIndexOutOfBoundsException" + "/内层try-catch");
}
throw new ArithmeticException();
}
catch(ArithmeticException e) {
System.out.println("发生ArithmeticException");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println( "ArrayIndexOutOfBoundsException" + "/外层try-catch");
}
}
}

结果:

catchwho2.java

 public class CatchWho2 {
public static void main(String[] args) {
try {
try {
throw new ArrayIndexOutOfBoundsException();
}
catch(ArithmeticException e) {
System.out.println( "ArrayIndexOutOfBoundsException" + "/内层try-catch");
}
throw new ArithmeticException();
}
catch(ArithmeticException e) {
System.out.println("发生ArithmeticException");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println( "ArrayIndexOutOfBoundsException" + "/外层try-catch");
}
}
}

结果:

分析:catchwho1按照内外层的try catch代码块一步一步执行

catchwho2结果的原因是内存try里的异常并没有被catch(ArithmeticException e)捕获到,故该字段异常,不执行此try catch块下的其他内容,而是此异常的ArrayIndexOutOfBoundsException()对象被外层的catch(ArrayIndexOutOfBoundsException e)捕获,打印出相应结果。

辨析:finally语句块一定会执行吗?

 public class SystemExitAndFinally {
public static void main(String[] args)
{
try{
System.out.println("in main");
throw new Exception("Exception is thrown in main");
//System.exit(0);
}
catch(Exception e){
System.out.println(e.getMessage());
System.exit();
}
finally{
System.out.println("in finally");
}
}
}

结果:

结论:在exit(0)下, finally里的语句块不会执行。

特别注意: 当有多层嵌套的finally时,异常在不同的层次抛出 ,在不同的位置抛出,可能会导致不同的finally语句块执行顺序。

如何跟踪异常的传播路径?

当程序中出现异常时,JVM会依据方法调用顺序依次查找有关的错误处理程序。

可使用printStackTrace 和 getMessage方法了解异常发生的情况: printStackTrace:打印方法调用堆栈。

每个Throwable类的对象都有一个getMessage方法,它返回一个字串,这个字串是在Exception构造函数中传入的,通常让这一字串包含特定异常的相关信息。

 // UsingExceptions.java
// Demonstrating the getMessage and printStackTrace
// methods inherited into all exception classes.
public class PrintExceptionStack {
public static void main( String args[] ){
try {
method1();
}
catch ( Exception e ) {
System.err.println( e.getMessage() + "\n" );
e.printStackTrace();
}
}
public static void method1() throws Exception {
method2();
}
public static void method2() throws Exception{
method3();
}
public static void method3() throws Exception{
throw new Exception( "Exception thrown in method3" );
}
}

输出结果:

受控与不受控的异常

throws语句:throws语句表明某方法中可能出现某种(或多种)异常,但它自己不能处理这些异常,而需要由调用者来处理。 当一个方法包含throws子句时,需要在调用此方法的代码中使用try/catch/finally进行捕获,或者是重新对其进行声明,否则编译时报错。

throws语句中声明的异常称为受控(checked)的异常,通常直接派生自Exception类。

RuntimeException(其基类为Exception) 和Error(基类为Throwable)称为非受控的异常。这种异常不用在throws语句中声明。

 import java.io.*; 

 public class CheckedExceptionDemo {
public static void main(String[] args) {
try {
BufferedReader buf = new BufferedReader(
new InputStreamReader(System.in)); //抛出受控的异常
System.out.print("请输入整数: ");
int input = Integer.parseInt(buf.readLine()); //有可能引发运行时异常
System.out.println("input x 10 = " + (input*));
}
//以下异常处理语句块是必须的,否则无法通过编译
catch(IOException e) {
System.out.println("I/O错误");
}
//以下异常处理语句块可以省略,不影响编译,但在运行时出错
catch(NumberFormatException e) {
System.out.println("输入必须为整数");
}
}
}

一个方法可以声明抛出多个异常:    int g(float h) throws OneException,TwoException { …… }

 import java.io.*;
public class ThrowMultiExceptionsDemo {
public static void main(String[] args) {
try {
throwsTest();
}
catch(IOException e) {
System.out.println("捕捉异常");
}
}
private static void throwsTest() throws ArithmeticException,IOException {
System.out.println("这只是一个测试");
// 程序处理过程假设发生异常
throw new IOException();
//throw new ArithmeticException();
}
}

在有继承关系中,一个子类的throws子句抛出的异常,不能是其基类同名方法抛出的异常对象的父类。

自定义异常与异常处理链

介绍一种被广泛使用的异常处理方法——通过自定义异常类捕获并处理业务逻辑错误 。

 class MyException extends Exception{
public MyException(String Message) {
super(Message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
}
public class ExceptionLinkInRealWorld {
public static void main(String args[]){
try {
throwExceptionMethod(); //有可能抛出异常的方法调用
}
catch ( MyException e ){
System.err.println( e.getMessage() +"--1");
System.err.println(e.getCause().getMessage()+"--2");
}
catch ( Exception e ){
System.err.println("Exception handled in main--3" );
}
doesNotThrowException(); //不抛出异常的方法调用
}
public static void throwExceptionMethod() throws MyException{
try {
System.out.println( "Method throwException--4" );
throw new Exception("系统运行时引发的特定的异--W"); // 产生了一个特定的异常
}
catch( Exception e ){
System.err.println("Exception handled in method throwException--5" );
//转换为一个自定义异常,再抛出
throw new MyException("在方法执行时出现异常-W",e);
}
finally {
System.err.println("Finally executed in throwException--6" );
}
// any code here would not be reached
}
public static void doesNotThrowException()
{
try {
System.out.println( "Method doesNotThrowException--7" );
}
catch( Exception e ){
System.err.println( e.toString() );
}
finally {
System.err.println("Finally executed in doesNotThrowException--8" );
}
System.out.println("End of method doesNotThrowException--9" );
}
} //

ExceptionLinkInRealWorld.java

结果:

在实际开发中,可以参照ExceptionLinkInRealWorld.java 示例的做法,定义一些与业务逻辑相关的自定义异常类,供上层代码进行捕获,从而能更精确地反映系统真实运行情况并及时进行处理。

关于开发中异常处理的建议

在中间层组件中抛出异常,在界面层组件中捕获异常,在底层组件中捕获JVM抛出的“只有程序员能看懂的”异常,转换为中间层的业务逻辑异常,再由界面层捕获以提供有意义的信息。

自身能够处理的异常,不要再向外界抛出。

尽可能地在靠近异常发生的地方捕获并处理异常。

尽可能地捕获最具体的异常类型,不要在中间层用 catch(Exception)“吃掉”所有异常。

在开发阶段捕获并显示所有异常信息,发布阶段要移除部分代码,以避免“过于专业”的异常信息困扰用户,特别地,系统发布之后,不要将服务端异常的详细信息发给客户端,以免被黑客利用。

最新文章

  1. Cocopod
  2. hadoop+tachyon+spark的zybo cluster集群综合配置
  3. View.setTag(key,object)异常:The key must be an application-specific resource id.
  4. ios xcode 下 报出 ”xx“is missing from working copy 的问题
  5. Centos和Redhat的区别和联系
  6. Spring学习进阶 (三) Spring AOP
  7. List对象分组排序算法
  8. BZOJ_1623:_[Usaco2008_Open]_Cow_Cars_奶牛飞车_(贪心)
  9. 2017-2-18 net 输入输出语句
  10. 用SSE指令计算点乘和累加
  11. [国嵌攻略][152][I2C总线介绍]
  12. 手把手教你用webpack3搭建react项目(开发环境和生产环境)(一)
  13. 聊聊Docker
  14. 图解CSS3核心技术与案例实战(1)
  15. Java反转二叉树
  16. hive函数应用之操作json
  17. Jenkins和gitlab集成自动构建
  18. 1.display:flex布局笔记
  19. (转载)C# GDI+ 画简单的图形:直线、矩形、扇形等
  20. 2018.09.27 codeforces618F. Double Knapsack(抽屉原理+构造)

热门文章

  1. noi.ac #553 序列
  2. docker之CPU配额参数的混合使用
  3. 「CF525D」Arthur and Walls
  4. Django的JWT机制工作流程
  5. 关于MongoDB在windows下安装【解压版】
  6. IDEA的小技巧:1.Java代码不被识别2.目录下创建的文件夹所显示样式不是文件夹,而是"包"图标样式的问题
  7. 关于PHP内部类的一些总结学习
  8. 石川es6课程---11、json
  9. Python基于Pymssql模块实现连接SQL Server数据库的方法
  10. hive 使用笔记(table format;lateral view横表转纵表)