Day(15)异常

异常

什么是异常

  • Exception,意思是例外

  • 异常发生在程序运行中出现的不期而至的各种状况

  • 异常在程序运行期间,影响了正常的程序执行流程

  • 简单分类:

    1. 检查性异常

    2. 运行时异常

    3. 出错

    4. 错误:错误不是异常,而是脱离程序员控制的问题

  • 异常处理框架

  • 异常体系结构

    • Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类

    • 在Java API中已经定义了许多异常类,这些异常分为两大类,错误Error和异常Exception

Error

  • Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关(系统级别的错误,属于严重问题)

  • Java虚拟机运行错误,当JVM不再有继续执行操作所需的内存资源时,将出现OutOdMemoryError。这些异常发生时,Java虚拟机一般会选择线程终止

  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、连接错误(LinkageError)。这些错误都是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数时程序运行时不允许出现的状况

Exception

  • RuntimeException(运行时异常)

  • ArrayIndexOutOfBoundsException(数组下标越界)

  • NullPointerException(空指针异常)

  • ArithmeticException(算术异常)

  • MissingResourceException(丢失资源)

  • ClassNotFoundException(找不到类)

  • 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;

  • Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

  • Exception:叫做异常,代表程序可能出现的问题。我们同窗会用Exception以及他的子类来封装程序出现的问题

  • 运行时异常:RuntimeException以及子类,编译阶段不会出现异常提醒,运行时出现的异常(如:数组索引越界)

  • 编译时异常:编译阶段就会出现异常提醒。(如:日期解析异常)

  • 编译阶段:java不会运行代码,只会检查语法错误,或者做一些性能上的优化。(提醒程序员检查本地信息)

  • 运行时异常:一般由于参数传递错误带来的问题

异常处理机制

  • 抛出异常

  • 捕获异常(捕获多个异常需要从小到大写)

  • 异常处理的五个关键字

    • try、catch、finally、throw、throws

  • 示例

    public class Test {
    ​
        public static void main(String[] args) {
          int a = 1;
          int b = 0;
    ​
            try{
                //try监控区域
                System.out.println(a/b);
            }catch(ArithmeticException e){
                //捕获异常catch想要捕获的异常类型
                //可以写多个catch,但异常类型要从小到大写
                System.out.println("程序出现异常,b不能为0");
            }finally {
                //finally监控区域,无论是否出现异常都会执行,处理善后工作
                System.out.println("finally");
            }
    ​
            //fianlly 可以不要,这是假
          设io,资源,关闭!
        }
    }
  • 在 Java 中,throwthrows是用于处理异常的关键字,它们的主要区别如下:

    • throw用于在程序中抛出异常。当程序执行到throw语句时,会立即抛出一个异常对象,并终止当前的执行路径。可以在任何地方使用throw抛出异常,通常用于检测到错误情况时主动抛出异常。

    • throws用于在方法签名中声明该方法可能抛出的异常列表。当在方法中使用throw抛出异常时,需要在方法声明中使用throws关键字来声明可能抛出的异常类型,以便调用者能够进行适当的异常处理。

  • try....catch

    一般用在调用处,能让代码继续往下运行

Finally

try {
    // 可能会抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型异常的代码
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型异常的代码
} finally {
    // 无论是否发生异常都会执行的代码
}
  1. 确保资源释放

    • 当在 try 块中打开了一些资源(如文件、数据库连接等),无论是否发生异常,都需要确保这些资源被正确关闭。finally 块提供了一个可靠的地方来执行资源释放的操作。

    • 例如,打开一个文件进行读取操作后,在 finally 块中关闭文件流:

       try {
           FileInputStream fis = new FileInputStream("file.txt");
           // 读取文件内容的代码
       } catch (FileNotFoundException e) {
           e.printStackTrace();
       } finally {
           if (fis!= null) {
               try {
                   fis.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
  2. 统一的清理逻辑

    • 在复杂的程序中,可能有多个地方可能抛出异常,但需要在无论哪种情况下都执行一些统一的清理操作。finally 块可以确保这些清理操作一定会被执行。

    • 比如,在一个方法中进行多个数据库操作,无论哪个操作出现异常,都需要在 finally 块中回滚事务:

       Connection conn = null;
       try {
           conn = getConnection();
           // 执行数据库操作
       } catch (SQLException e) {
           e.printStackTrace();
       } finally {
           if (conn!= null) {
               try {
                   if (!conn.getAutoCommit()) {
                       conn.rollback();
                   }
                   conn.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }
  3. 注意事项

    1. finally 块一定会执行,但也有一些特殊情况:

      • 如果在 try 或 catch 块中执行了 System.exit(0) 方法,这将导致程序立即终止,finally 块不会被执行。

      • 如果在 try 块中发生了严重的错误导致 JVM 崩溃,finally 块也可能不会被执行。

    2. finally 块中的 return 语句:

      • 如果 finally 块中有 return 语句,那么这个 return 语句会覆盖 try 或 catch 块中的 return 语句。

      • 例如:

       public static int testMethod() {
           try {
               return 1;
           } catch (Exception e) {
               return 2;
           } finally {
               return 3;
           }
       }

    在这个例子中,无论是否发生异常,最终都会返回 3,因为 finally 块中的 return 语句覆盖了 try 和 catch 块中的 return 语句。

抛出处理

throws

注意:写在方法定义处,表示声明一个异常。告诉调用者,使用本方法可能会有哪些异常

public void 方法() throws 异常类名1,异常类名2...{
    ...
}

编译时异常:必须要写

运行时异常:可以不写

throw

注意:写在方法内,结束方法

手动抛出异常对象,交给调用者

方法中下面的代码不再运行

publicl void 方法(){
    throw new NullPointerException();
}

自定义异常

  • 步骤

    1. 创建自定义异常类

    2. 在方法中通过throw关键字抛出异常对象

    3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作

    4. 在出现一场方法的调用者捕获并处理异常

    5. 总结:定义异常类、写继承关系、空参构造、带参构造

  • 意义:为了让控制台的报错信息更见名知意

  • public class Test {
        static void test(int a) throws MyException{
            System.out.println("传递的参数是:"+a);
    ​
            if(a>10){
                throw new MyException(a);//抛出
            }
    ​
            System.out.println("ok");
        }
    ​
        public static void main(String[] args) {
            try {
                test(11);
            } catch (MyException e) {
                System.out.println("MyException:"+e);
            }
        }
    }
  • 异常里的常用方法

    public String getMessage()  //返回此throwable 的详细消息字符串
    public String toString()    //返回此可抛出的简短描述
    public void printStackTrace()  //在底层用System.err.println进行输出。把异常的错误信息输出在控制台(仅仅是打印信息,不会停止程序运行)

实际应用中的经验总结

  • 处理运行的异常时,采用逻辑去合理规避同时赋值try-catch处理

  • 在多重catch块后面,可以加一个caych(Exception)来处理可能会被遗漏的异常

  • 对于不确定的代码,也可以加上try-catch,处理潜在异常

  • 尽量处理异常,切记只是简单的调用printStackTrace()去打印输出

  • 具体如何处理异常,要根据不同的业务需求和异常类型去决定

  • 尽量添加finally语句块去释放占用的资源

如果try中没有遇到问题,怎么执行?

  • 会把try里面所有的代码全部执行完毕,不会执行catch里面的代码

如果try中可能会遇到多个问题,怎么执行?

  • 会写多个catch与之对应

  • 父类异常需要写在下面

如果try中遇到的问题没有被捕获,怎么执行?

  • 相当于try....catch白写了,当前异常交给虚拟机处理

如果try中遇到了问题,那么try下面的其他代码还会执行吗?

  • 不会。try中遇到的问题直接跳转到对应的catch如果没有对应的catch与之匹配,则交给虚拟机处理

  • 抛出:告诉调用者出错了

    捕获:不让程序停止

  • 方法需要抛出运行时期异常的时候可以省掉,方法体中的不能省

拓展

正常的输出语句: System.out.println(123);//此时输出的语句就是黑色

错误的:System.err.println(123);//此时输出的语句就是红色

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值