Java的异常那些事

Throwable类

在我们利用编译工具进行Java程序编写时,通常会遇到各种错误提示我们需要抛出异常,也会遇到编译失败的情况提示我们哪里出现了错误,那么这些异常和错误的提示是来自哪里呢?
在Java的java.lang包中,有一个类叫Throwable,而我们遇到的异常和错误均是Throwable类的子类。

那么什么是异常什么是错误呢?

  • 异常Exception:(错了,但问题不大)异常一般情况程序是可以自行处理的,利用catch来捕获或抛出。但并不是所有的异常都需要处理,有时候一些异常是无关紧要的,此时可以不对该类异常进行处理。为了区分这种情况,异常也可以分为两类**:受检查异常(Checked Exception)不受检查异常(Unchecked Exception)**
  • 错误Error:(错了,问题很严重无法编译)错误一般是程序无法自行处理的。出现错误后,一般JVM都会终止线程。

受检查异常与不受检查异常

  • 受检查异常:该类异常如果遇到就必须对其进行捕获或者抛出,否则无法编译。一般情况除了RuntimeException及其子类都是受检查异常。
  • 不受检查异常:该类在编译过程中即使不对其进行处理仍然能够编译,一般RuntimeException及其子类都是不受检查异常。常见的有:NullPointerException (空指针错误)、ArrayIndexOutOfBoundsException (数组越界错误)、ClassCastException (类型转换错误)、SecurityException (安全错误⽐如权限不够)、NumberFormatException (字符串转换为数字格式错误)等。

那么如何查看异常的相关信息呢?

这里Throwable类提供了几个方法来查看异常信息:

  • String getMessage() : 返回异常发⽣时的简要描述
  • String toString() : 返回异常发⽣时的详细信息
  • String getLocalizedMessage() : 返回异常对象的本地化信息。(这里需要使⽤ Throwable 的⼦类覆盖这个⽅法,如果没有覆盖那么返回的信息与 getMessage() 返回的结果相同)
  • void printStackTrace() : 在控制台上打印 Throwable 对象封装的异常信息

那么如何处理这些异常呢?

这里就不得不提到常用的几个处理异常的块:try、catch、finally

  • try:可以捕获异常
  • catch:可以处理try捕获到的异常
  • finally:在该块内的程序,无论是否捕获或者是否处理异常都能执行
    当我们利用try捕获异常后,是可以选择接零个或多个catch块的,即可以选择不对异常进行处理也可以进行多个处理。但是在不进行处理(没有catch块时)必须跟一个finally块。finally块一般都是要执行的,**即使在try和catch块中出现return语句也要在返回之前把finally块内的程序执行。**但也正是因为这种机制,所以finally块内不能使用return语句,因为当finally块内有return时,try和catch中的return返回值会被暂时存储在一个本地变量内,此时执行finally内的return后,本地变量内的返回值则变为finally内的return返回值。

前面也说了finally块一般是都要执行的,那么有没有特殊情况呢?有!

  1. 在执行finally 块之前虚拟机被终⽌运⾏的话,finally 中的代码就不会被执⾏
  2. 程序所在的线程死亡
  3. 关闭 CPU

在使用try、catch、finally处理异常时还有一个问题,即很多情况下我们需要对资源进行管理,但是利用try、catch、finally管理会很复杂,代码较乱。

try-with-resourse

try-with-resourse是什么呢?
try-with-resourse是一种可以代替try、catch、finally的更好的管理资源的异常处理机制。例如:InputStream 、 OutputStream 、 Scanner 、PrintWriter 等的资源都需要调⽤ close() ⽅法来⼿动关闭

例如:

    /**
     * try、catch、finally
     */
    public static void test1() {
        String filePath = "D:\\test1\\test1.txt";
        FileOutputStream fileOutputStream = null;
        FileInputStream fileInputStream = null;
        try {
            fileOutputStream = new FileOutputStream(new File(filePath));
            fileInputStream = new FileInputStream(new File(filePath));
            // 写
            fileOutputStream.write("ab1024".getBytes(Charset.defaultCharset()));
            // 读取
            int data = fileInputStream.read();
            while (data != -1) {
                System.out.print((char) data);
                data = fileInputStream.read();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭写流
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    // 关闭读流
                    if (fileInputStream != null) {
                        try {
                            fileInputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
 
        }
    }

此时可以看出代码量是很大的,很复杂不易管理,需要在finally块中对多个数据流资源进行关闭处理。
因此可以使用try-with-resourse来改进:

/**
 * 自动关闭资源 try-with-resource
 */
public static void test2() throws Exception {
    String filePath = "D:\\test1\\test1.txt";
    // java7中的try-with-resource,java9中有所改善
    try (FileOutputStream fileOutputStream = new FileOutputStream(new File(filePath));
         FileInputStream fileInputStream = new FileInputStream(new File(filePath))) {
        // 写
        fileOutputStream.write("ab1024".getBytes(Charset.defaultCharset()));
        // 读取
        int data = fileInputStream.read();
        while (data != -1) {
            System.out.print((char) data);
            data = fileInputStream.read();
        }
    }
}

此时代码得到了明显的优化,在这里可以通过分号声明多个资源,例如上面的 fileOutputStream 与 fileInputStream

注意

最后,处理异常不要时不要把异常声明为静态变量,由于静态变量是存储在栈中的,这样我们下次对新的异常抛出时,可能是从栈中提取,异常会出现错乱现象。当然我们也不能随意抛出异常,一个异常一定要有意义,而且需要具体,⽐如字符串转换为数字格式错误的时候应该抛出NumberFormatException ⽽不是其⽗类 IllegalArgumentException 。(错误需要更具体才能针对性解决) 如果打印了异常日志那么就不需要抛出了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值