java异常处理机制

异常处理机制

   异常并非语法错误,若语法错误,编译不通过,不会产生字节码文件,不能运行。异常处理衡量一门语言是否成熟的标准之一。异常处理机制可以让程序有更好的容错性,代码更健壮

C语言没有异常处理机制,所以经常使用特定返回值来表示异常情况,然后使用if语句来判断正常和非正常关系, if-else就是异常处理的一种


 没有异常处理机制存在的缺点:
 1. 使用方法的返回值来表示异常的情况有限,无法穷举所有的异常情况。
 2. 异常流程和正常代码混合在一起,增大了程序的复杂性,可读性不好。
 3. 随着系统规模的扩大,程序的可维护性极低(耦合度太高)。

 Java异常体系
 
 1. 把不同类型的异常情况描述成不同的异常类
 2. 分离异常流程代码和正确流程代码
 3. 灵活处理  如何当前方法处理不了,交给调用者处理
 
 非正常情况:
 1. error:表示错误,一般指JVM相关的不可修复的代码,如系统崩溃,内存溢出,JVM错误,由JVM抛出,不需要处理

几乎所有的子类都以Error作为类的后缀


 2. Exception:表示异常,指程序出现不正常的情况,该问题可以修复(处理异常),几乎所有的子类都是以Exception作为类型的后缀, XXXException
 
 抛出异常
 1.使用throw在方法内部,抛出一个异常对象
 2.使用throws在方法的声明上,抛出一个异常对象


   throw当一个方法出现未知异常的时候,抛出一个具体的异常类型,和return一样会结束当前方法

1. 用在方法体内,跟的是异常对象名

2.只能抛出一个异常对象名

3.表示抛出异常,由方法体内的语句处理

4.执行throw则一定抛出了某种异常 

  throws用来声明一个方法可能产生的所有异常当前方法不处理异常,而是将异常往上传,谁调用我我就抛给谁。如果每一个方法都放弃异常处理都直接通过throws声明抛出,最后异常会抛到main方法,如果main方法也不处理,就会继续抛出给JVM,底层的处理机制就是打印异常的跟踪栈信息

1.用在方法声明后面,跟的是异常类名,可以跟多个异常类名,用逗号隔开。

2.throws表示出现异常的一种可能性,并不一定会发生这些异常

3.表示抛出异常,由该方法的调用者来处理

   //在本例中,异常由方法体内的语句处理

   public
static void main(String[] args) { int num1,num2; num1 = 10; num2 = 0; System.out.println(divide(num1,num2)); } private static int divide(int num1,int num2) { System.out.println("begin........"); if(num2 == 0) { throw new ArithmeticException("除数不能为0"); } try { int ret = num1/num2; System.out.println("结果" + ret); } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("end..........."); return 0; }
   //除数为0,得到这样的结果:
   /*
       begin........
       Exception in thread "main" java.lang.ArithmeticException: 除数不能为0
       at com.tedu.day08.ThrowDemo.divide(ThrowDemo.java:55)
       at com.tedu.day08.ThrowDemo.main(ThrowDemo.java:47)
     */ }

捕获和处理异常
 try catch
 try catch finally
 try finally

以上的异常处理语法结构中
注意:

1. 只有try块是必须的,也就是说如果没有try块,则不可能有后面的catch块和finally块;
2. catch块和finally块都是可选的,但catch块和finally块至少出现其中之一,也可以同时出现;
3. 可以有多个catch块,捕获父类异常的catch块必须位于捕获子类异常的后面
4. 不能只有try块,既没有catch块,也没有finally块;
5. 多个catch块必须位于try块之后,finally块必须位于所有catch块之后。

public static void main(String[] args) {
        //使用try-catch捕获异常
        /*
         * 使用try—catch捕获单个异常  (或多个异常)
         * try{
         *     编写可能会出现异常的代码
         * }catch(异常类型 e){
         *     处理异常的代码1
         *     //记录日志  打印异常信息 继续抛出异常
         * }catch(异常类型){
         *     异常处理2
         * }
         * 
         * 1.一个catch语句,只能捕获一种类型的异常,如果捕获多个,就必须使用多个catch语句
         * 2.代码在一瞬间只能出现一种类型的异常,只需要一个catch捕获,不可能同时出现多个异常
         * try{
         * 
         * }
         * catch(Exception e){//必须放到最后
         * }
         * 
         * try—catch必须连用
         * -------------------------------------------
         * 如何获取异常信息,使用Throwable类的方法
         * 1.getMessage()  获取异常的描述信息,原因提示给用户的时候  就提示错误原因
         * 
         * 2.toString()  获取异常的类型和异常描述信息
         * 
         * 3.printStackTrace()  打印异常的跟踪栈信息  并且输出都控制台,包含异常的类型,异常的原因还包括了异常出现的位置,在开发和调试阶段都
         * 得使用printStackTrace()
         * 
         * 注意:
         * 现在catch语句中,必须写e.printStackTrace()
         * 查看异常位置 信息
         */
        try {
            int ret = 10/0;
            System.out.println("结果" + ret);
        }catch(Exception e) {
            System.out.println("异常消息:" + e.getMessage());
            System.out.println("异常消息: " + e.toString());
            //打印信息到控制台
            e.printStackTrace();
        }
        System.out.println("---Throwable类,如何捕获异常信息");
    }
}

再看看finally的用法

finally

/*
 * finally  表示一个代码块
 * 特点:无论是否有异常,最终都会执行finally代码块  (有特殊情况,JVM退出)
 * 目的:释放资源
 * ---------------------------------------------
 * 比如当我们的try语句中开了一个物理资源(数据库,网络)
 * 都得在使用完之后,最终关闭打开的资源
 * ----------------------------------------------
 * finally
 * 1.try - finally  
 * 会有catch捕获异常,根据场景,抛出异常,不需要自己处理
 * 
 * 2.try - catch - finally 
 * 自身需要处理异常  最终还需要关闭资源
 * 注意:finally不能单独使用
 * ----------------------------------------------
 * 当只有在try 或者 catch 中调用退出JVM的方法  才不会执行finally (System.exit(0));
 * 否则finally一定会执行
 * ----------------------------------------------------------------------------
 * 
 * final修饰符,定义常量
 * finally代码块(特点如上)
 * finalize方法,垃圾回收机制
 * 
 * 
 */

public class FinallyDemo {
    public static void main(String[] args) {
        
//      text1();
        
        System.out.println(text2());
        
//      System.out.println(text3());
//        
//      System.out.println(text4());
        
    }
    
    private static int text4() {//返回1
        int a = 1;
        try {
            return a;
        } finally {
            return a++;
        }
    }
    
    
    private static int text3() {//返回2
        int a = 1;
        try {
            return a;
        } finally {
            return ++a;
        }
    }
    //如果finally语句里面带有return语句
    //永远返回的是finally里面的值
    //需要避免该情况
    private static int text2() {
        try {
            System.out.println("aa");
            return 1;
        } finally {
            System.out.println("bb");
            return 100;//finally返回值会把try里面的返回值覆盖  这里返回100
        }
    }

    private static void text1() {
        System.out.println("begin.....");
        try {
            int ret = 0/0;
            System.out.println("结果" + ret);
        } 
        catch (Exception e) {
            System.out.println("异常");
        } 
        finally {
            System.out.println("关闭资源");
        }
        System.out.println("end......");
        
    }
}
/*
使用finally回收资源

有时候,程序在try块里面打开了一些物力资源(比如数据库连接,网络连接好磁盘文件等),这些物理资源都必须显式回收。因为java的垃圾回收机制不会回收任何的物理资源
垃圾回收机制只回收堆内存中对象所占用的内存。


问题:那么在哪边回收这些物理资源呢?

答:在finally块中,因为如果try块的某条语句引起一场,该语句后的其他语句通常不会被执行,那将导致位于该语句后的资源回收语句得不到执行;如果在catch块里进行资源回收
但catch块完全有可能得不到执行,这也将导致不能及时回收这些物理资源。所以我们不管try块中的代码是否出现异常,也不管哪个catch块会被执行,finally块总会被执行。

那么:java异常处理的完整语法结构如下:

try
{
     //业务实现逻辑
     ...
}
catch(SubException e)
{
     //异常处理块1
     ...
}
catch(SubException2 e)
{
     //异常处理块2
     ...
}
     ...
finally
{
    //资源回收块
    ...
}

参考:

https://blog.csdn.net/weixin_38011265/article/details/79149313

坚持学习,永远年轻,永远热泪盈眶
原文地址:https://www.cnblogs.com/jiang0123/p/11295122.html