异常Exception详解

【1】异常的划分

1)按继承体系划分:分为两个子类,一个是ERROR(错误),另一个是Exception(异常)
                                  错误属于比较严重的,异常属于可以恢复的错误。
2)按检查和未检查划分:分为检查异常(蓝色方框)和未检查异常(红色方框)。
     区别:检查异常需要配合try-catch或throws关键字一起使用,       否则会引起编译错误。
                未检查异常:用不用关键字都可以。

  • 检查异常:该异常在编译时,如果没有处理(没有throw,也买有try),编译失败。该异常被标识,代表这可以被处理。
  • 未检查异常:在编译时不需要处理,编译器不检查。该异常发生时,建议不处理,让程序停止,需要对代码进行修正。

【2】异常的语法

1)积极处理
    try{
    可能引发异常的语句
    }catch(Exception){
        捕捉到的异常信息
    }finally{-----无论上面的catch是否能捕捉到真正的异常,都会执行的语句(这步操作根据需求添加)
        一定会执行的语句
    }
简单的理解:try中的语句就是可能会引起异常,而异常会导致程序中止,如果catch可以捕捉到上述的异常,那么就可以使程序正常运行。*不管是否捕捉到对应的异常,finally中的语句都是要执行的。*

特殊的4种情况,finally语句块不会被执行:

                              1)在finally语句块中发生了异常。

                              2)在前面的代码中使用了System.exit()退出程序。

                              3)程序所有的线程死亡。

                              4)  关闭CPU。
    当然一个try后面可以跟上多个catch语句,这些catch中的内容是并列的或是继承关系。如果是继承关系,需注意父类不能写在子类的前面。
2)消极处理
      给出throws。
      如果语句中存在异常,没有try-catch关键字,那么异常发生时,会将异常传递给方法的调用者,这时候需要在方法声明上抛出异常。
      如果方法中出现的的是检查异常,则必须给出throws,如果是未检查异常,则可以给也可以不给。

举例:

public class Demo1 {
    /*
    处理方式一:抛出异常给jvm虚拟机,让虚拟机处理这个异常(虚拟机的处理方法是调用printStackTrace方法,打印异常信息)
    public static void main(String[] args) throws Exception {
        int x=div(12,0);
        System.out.println(x);
        
        
    }*/
    public static void main(String[] args) {
        int x= 0;
        /*处理方式二:用try...catch捕获异常*/
        try {
            x = div(12,0);
            System.out.println(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    public static int div(int a,int b) throws Exception{
        return a/b;
    }
}

 【3】异常的常用方法

         getMessage()---返回的是异常的信息
         getStackTrace()---打印异常的跟踪信息,打印堆栈中的异常出现位置,异常(名称、信息)。

在JVM默认的异常处理机制,就是调用printStackTrace方法,打印异常的堆栈跟踪信息。
         创建异常类:
           1)class MyException extends Exception{ // 检查异常 }
           2)class MyException extends RuntimeException { // 未检查异常}

【4】异常处理的原则

1.函数内容如果抛出需要检测的异常,那么函数上必须声明,否则必须在函数内用try{}catch(){}捕捉,否则编译失败。

2.如果调用到了声明异常的函数,要么trycatch要么throws,否则编译失败。

3.什么时候使用catch,什么时候使用throws?

     功能内容可以解决,用catch;解决不了,用throws告诉调用者,由调用者解决。

4.一个功能如果抛出了多个异常,那么调用时,必须有对应的多个catch进行针对性的处理。

【5】自定义异常

在项目中会出现特有的问题,而这些问题并未被java所描述并封装为对象,所以对于这些特有的问题可以按照java封装的思想,将特有的问题进行自定义的异常处理。

如何定义异常信息?

因为父类中已经将异常信息的操作都完成了,所以子类只需要在构造时,将异常信息通过super()传递给父类,就可以直接地通过getMessage()方法获取自定义得到异常信息。

自定义异常类必须继承Exception,原因:因为异常类和ichang对象都被抛出,他们都有可抛性。只有Throwable体系中的类和对象才可以被throws和throw操作。

步骤:     

  • 创建自定义异常类
  • 在方法中通过throw关键字抛出异常
  • 如果在当前抛出的异常方法中处理异常,可以使用try-catch语句块捕获并处理,否则在方法的声明处通过throws关键字指名要抛出给方法调用者的异常,继续下一操作。
  • 在出现异常方法的调用者中捕获并处理异常。

举例:

public class MyException extends Exception {
    private int value;
    MyException(){
        super();
    }
    MyException(String msg,int value){
        super(msg);
        this.value=value;
    }
    public int getValue(){
        return value;
    }
}

public class Demo2 {
    public int div(int a,int b) throws MyException {
        if(b<0){
            throw new MyException("出现了除数是负数的情况",b);
        }
        return a/b;
    }

    public static void main(String[] args) {
        Demo2 d=new Demo2();
        try {
            int x=d.div(12,-4);
        } catch (MyException e) {
            System.out.println(e.toString());
            System.out.println("错误的负数是:"+e.getValue());
        }
    }
}

【6】throw、throws

  如果某个方法可能发生异常,但又不想立刻处理,则可以使用throws或者throw关键字在方法中抛出异常,但最终要有能够处理该异常的代码。

  1.   throws通常被应用在声明方法时。多个异常可使用逗号分隔。
  2.   RuntimeException、Error或是他们的子类,可以不使用throws关键字抛出异常,编译仍能通过,但在运行时会被系统抛      出。
  3. throw关键字用于方法体中,并且抛出一个异常对象。程序在执行到throw语句时立即终止,后面语句不执行。通过throw抛出异常后,若想在上一级代码中捕获并处理异常,则需要在抛出的异常方法中使用throws在方法声明中指明要抛出的异常;如果要捕捉throw抛出的异常,必须使用try-catch语句块。
  4. throw通常用来抛出用户自定义异常。

【7】try...catch...finally

格式一:
try{
    ...
}catch(Exception e){
    ...
}finally{
    //存放一定会被执行的代码,通常用于资源的关闭
}

格式二:

try{

...

}finally{

//存放一定会被执行的代码,通常用于资源的关闭

}

格式三:

try{

}catch(){

/**
 * try{
 *     
 * }catch(Exception e){
 *     
 * }finally{
 *     
 * }
 */


public class Demo3 {
    //编译可以通过
    public void method1(){
        try {
            throw new Exception();
        }catch (Exception e){
            
        }
    }
    
    //编译不能通过,异常未被声明
    public void method2(){
        throw new Exception();
    }
    
    //编译可以通过
    public void method3() throws Exception{
        try {
            throw new Exception();
        }catch (Exception e){
            try {
                throw e;
            }catch (){
                
            }
        }
    }
    
    //编译不能通过
    public void method4(){
        try{
            throw new Exception();
        }finally{
            
        }
    }
    //结论:没有catch块,异常就不能被处理,只能声明(抛出去)。否则编译就不能通过。
    
}

【7】RuntimeException运行时异常

RuntimeException及其子类,如果在函数内抛出异常,函数上可以不用声明,编译一样会通过。如果函数上声明了该异常,调用者可以不进行处理,编译同样通过。之所以不用在函数声明,是因为不需要让调用者处理,当该异常发生时,希望程序停止,因为在运行时出现了无法继续运算的情况,希望停止程序,对代码进行修正。

【8】异常在子父类中的体现

1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类。

2.如果父类抛出异常多个,那么子类在覆盖方法,只能抛出父类异常的子集。

3.如果子类发生父类没有的异常(或者父类异常的子类异常),那么子类就只能在内部处理该异常,不能抛出。

4.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时也不可以抛出异常。如果子类方法发生异常,就必须要进行try{}catch(){}处理,不能抛出异常。

【9】finally与return 的执行顺序

/**
 * 异常中的return
 */
public class Demo5 {
    public static void main(String[] args) {
        /*int x1=method1();
        System.out.println(x1);
        输出:
        finally
        1
        */
        /*int x2 = method2();
        System.out.println(x2);
        输出:
        finally
        2*/
        
        /*int x3 = method3();
        System.out.println(x3);
        输出:
        finally
        0*/
        
        /*int x4 = method4();
        System.out.println(x4);
        输出:
        finally
        0
        结论:如果try...catch中的return返回的是一个变量,且函数是从其中一个返回时,
        后面finally中语句即使有对返回值的操作,也不影响返回值的值。
        */
    }
    public static int method1(){
        try{
            
            return 1;
        }finally{
            System.out.println("finally");
        }
    }
    
    public static int method2(){
        try{
            int a=8/0;
            return 1;
        }catch (Exception e){
            return 2;
        }finally {
            System.out.println("finally");
        }
    }
    
    public static int method3(){
        try{
            int a=8/0;
            return 1;
        }catch (Exception e){
            return 2;
        }finally {
            System.out.println("finally");
            return 0;
        }
    }
    
    public static int method4(){
        int result=0;
        try{
            return result;
        }finally {
            System.out.println("finally");
            result= 1;
        }
    }

    //错误:缺少返回语句(如果不抛出异常,那么这个方法中就没有返回值)
    public static int method5(){
        int result=0;
        try{
            int re=10/0;
        }catch (Exception e){
            result=10;
            return result;
        }finally {
            System.out.println("finally");
        }
        
    }
}

【10】异常的注意事项

  1.   方法重写---子类方法不能比父类抛出更多的异常,子类重写的方法可以不抛出。
  2.   将检查异常包装为未检查异常。(建议)
  3.   不要吞异常---即catch块后面什么也不写,这样即使将来产生异常,也不知道是什么异常。
  4.   如果try,catch,finally中都有return以finally中的为准     如果try中有return,即使finally对return后的值做了改动,也不会影响    到返回后的结果。
  5. 在调用方法时,方法的类型不为void,则在try块和catch块中,都需要加入return(前提,不存在finally中的returun)
  6. 当调用的方法出现检查异常或自定义异常,则在调用时,如果使用try-catch(积极处理),则可以正常使用,不用一级一级的向上抛出;如果使用throws(消极处理),则必须一级一级的向上抛出。---如果为未检查异常,则不需要加以处理。
  7. 如果catch捕获的异常不完整,则编译不会通过。 
  8. 异常产生后,如果不做任何处理,程序就会被终止。
  9. 一个方法被覆盖时覆盖它的方法必须抛出相同的异常或异常的子类。如果父类抛出多个子类,则覆盖方法必须抛出那些异常的子类,不能抛出新的异常。
  10. 与有返回值的方法连用时要注意:
public class Exception5 {
    public static int test(){
        try {
            Scanner scanner = new Scanner(System.in);
            int n = scanner.nextInt();
            int r = 1/n;
            return r;
        } catch (Exception e ) {
            System.out.println(e.getMessage());
            return -1; // 解决方法1: 在catch也写一个return返回结果
//            throw e; // 解决方法2: 把异常重新抛出
        }
    }

    public static void main(String[] args) {
        int r = test();
        System.out.println(r);
    }
}

【11】常见的异常

  • 数组下标越界--->ArrayIndexOutOfBoundsException 
  • 访问null的对象的方法或属性(空指针异常)--->NullPointerException
  • 类型转换异常--->ClassCastException
  • 未找到相应类异常--->ClassNotFoundException
  • 遍历集合的同时remove--->ConcurrentModificationException(并发修改异常)
  • 算术异常(除零)--->ArithmeticException
  • 在堆内存耗尽时--->OutOfMemoryError(new的太多了)
  • 在栈内存耗尽时--->StackOverflowError(应用程序递归太深而发生堆栈溢出)
  • 数组中包含不兼容的值抛出的异常--->ArrayStoreException
  • 操作数据库异常类--->SQLException
  • 字段未找到异常--->NoSuchFieldException
  • 方法未找到抛出的异常--->NoSuchMethodException
  • 字符串转化为数字异常--->NumberFormatException
  • 数组元素为负数抛出的异常--->NegativeArraySizeException
  • 字符串索引超出范围--->StringIndexOutBoundsException
  • 输入输出异常--->IOExceotion
  • 不允许访问某类异常--->IllegalAccessException
  • 文件已结束异常--->EOFException
  • 文件未找到异常--->FileNotFoundException

好长时间没做过总结了,感觉总结还是很重要的,总结的时候会搞清楚很多东西,还会给杂乱的知识框架化。。。希望诸位学习完之后也做做总结。
       日常鸡汤:你的人生永远不会辜负你就自己,那些走错的路

                         全都会让你成为独一无二的自己。。。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值