【Java学习笔记】异常处理

一 异常分类

(1)可检查的异常:编译时检查,必须捕捉或声明。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。

(2)不可检查的异常:编译时不受检查,不需要捕捉或声明。包括error和runtime exception。

       runtime exception:如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。

           Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的


二 捕获异常 try、catch 和 finally

try-catch-finally 规则

(1)必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。

(2)必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。

(3)catch 块与相应的异常类的类型相关。

(4)一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块

(5)可嵌套 try-catch-finally 结构。

(6)在 try-catch-finally 结构中,可重新抛出异常。

(7)除了下列情况,总将执行 finally 做为结束:JVM 过早终止(调用 System.exit(int));在 finally 块中抛出一个未处理的异常;计算机断电、失火、或遭遇病毒攻击。

try、catch、finally语句块的执行顺序:

1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;

2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;

3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;

finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。

三 throws抛出异常

   如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。例如汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理。

     throws语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是Exception异常类型,则该方法被声明为抛出所有的异常。多个异常可使用逗号分割。throws语句的语法格式为:

void method1() throws IOException{}  //合法    
   
//编译错误,必须捕获或声明抛出IOException    
void method2(){    
  method1();    
}    
   
//合法,声明抛出IOException    
void method3()throws IOException {    
  method1();    
}    
   
//合法,声明抛出Exception,IOException是Exception的子类    
void method4()throws Exception {    
  method1();    
}    
   
//合法,捕获IOException    
void method5(){    
 try{    
    method1();    
 }catch(IOException e){…}    
}    
   
//编译错误,必须捕获或声明抛出Exception    
void method6(){    
  try{    
    method1();    
  }catch(IOException e){throw new Exception();}    
}    
   
//合法,声明抛出Exception    
void method7()throws Exception{    
 try{    
  method1();    
 }catch(IOException e){throw new Exception();} 
 一个方法定义中throws异常的依据如下:
     1)方法中有throw语句。例如,以上method7()方法的catch代码块有throw语句。
     2)调用了其他方法,其他方法用throws子句声明抛出某种异常。例如,method3()方法调用了method1()方法,method1()方法声明抛出IOException,因此,在method3()方法中可能会出现IOException。


四 使用throw抛出异常

   throw总是出现在函数体中用来抛出一个Throwable类型的异常程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
  我们知道,异常是异常类的实例对象,我们可以创建异常类的实例对象通过throw语句抛出。该语句的语法格式为:
    throw new exceptionname;
    例如抛出一个IOException类的异常对象:
    throw new IOException;
    要注意的是,throw 抛出的只能够是可抛出类Throwable 或者其子类的实例对象。下面的操作是错误的:
    throw new String("exception");

这是因为String 不是Throwable 类的子类。

 如果抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型。该方法的调用者也必须检查处理抛出的异常。

 如果所有方法都层层上抛获取的异常,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈信息。如果抛出的是Error或RuntimeException,则该方法的调用者可选择处理该异常。

package Test;  
import java.lang.Exception;  
public class TestException {  
    static int quotient(int x, int y) throws MyException { // 定义方法抛出异常  
        if (y < 0) { // 判断参数是否小于0  
            throw new MyException("除数不能是负数"); // 异常信息  
        }  
        return x/y; // 返回值  
    }  
    public static void main(String args[]) { // 主方法  
        int  a =3;  
        int  b =0;   
        try { // try语句包含可能发生异常的语句  
            int result = quotient(a, b); // 调用方法quotient()  
        } catch (MyException e) { // 处理自定义异常  
            System.out.println(e.getMessage()); // 输出异常信息  
        } catch (ArithmeticException e) { // 处理ArithmeticException异常  
            System.out.println("除数不能为0"); // 输出提示信息  
        } catch (Exception e) { // 处理其他异常  
            System.out.println("程序发生了其他的异常"); // 输出提示信息  
        }  
    }  
  
}  
class MyException extends Exception { // 创建自定义异常类  
    String message; // 定义String类型变量  
    public MyException(String ErrorMessagr) { // 父类方法  
        message = ErrorMessagr;  
    }  
  
    public String getMessage() { // 覆盖getMessage()方法  
        return message;  
    }  
}  


上述代码使用了自定义异常使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。

    在程序中使用自定义异常类,大体可分为以下几个步骤。
(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。



部分内容整理自网络

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值