写点什么

聊聊 Java 的异常机制问题

发布于: 2021 年 03 月 30 日

摘要: java 异常指在程序运行时可能出现的一些错误,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间,中断了正在执行的程序的正常指令流。


本文分享自华为云社区《Java知识点问题精选之异常机制》,原文作者:breakDraw 。


java 异常指在程序运行时可能出现的一些错误,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间,中断了正在执行的程序的正常指令流。

 

Java 通过 API 中 Throwable 类的众多子类描述各种不同的异常。因而,Java 异常都是对象,是 Throwable 子类的实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。对于运行时异常、错误或可查异常,Java 技术所要求的异常处理方式有所不同。    

异常体系分类


Q: Throwable 和 Error 的关系

A: Throwable 是 Error(错误)的基类,也是 Exception 的基类

1 个好图,可看到常见的异常和 error



Q: Error 和 Exception 的关系

A:

  • Error 一般是会直接引起 jvm 出错的错误,例如 Java 虚拟机运行错误等,如果出现了当前线程会无法继续运行。

  • Excpetion 是程序本身可以处理的异常。发生后还能正常运行。


Q: Error 可以被 catch 捕捉吗?

A: 只要是 Throwable 和其子类都是可以 throw 和 catch 的。 但是不建议捕捉 Error。


异常体系还可以分为这 2 类:

  • unchecked exception(非检查异常)

也称运行时异常(RuntimeException),比如常见的 NullPointerException、IndexOutOfBoundsException。对于运行时异常,java 编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。


  • checked exception(检查异常,编译异常)

也称非运行时异常(运行时异常以外的异常就是非运行时异常),java 编译器强制程序员必须进行捕获处理,比如常见的 IOExeption 和 SQLException。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过。

异常捕捉和返回


Q: return-finally 陷阱 1: finally 能通过修改变量,来更新 return 的变量值吗

int f() {  int a = 1;  try {      return a;  }  finally {      a=2;  }}
复制代码

A: 不能, f 返回 1。


Q: return-finally 陷阱 2: finally 里也 return 时,返回哪个?

int f() {  try {      return 1;  }  finally {      return 2;  }}
复制代码

A:返回 finally 里的,返回 2。


Q: 什么情况下 finally 块里的步骤可以不执行?

A: 只有在 finally 之前调用 System.exit(0)退出 jvm, 才能让 finally 不执行。


Q: 下面会发生什么?

try {    start();} catch (Exception ex) {    System.out.println("catch Exception");} catch (RuntimeException re) {    System.out.println("catch RuntimeException");}
复制代码

A: 直接编译就错误了。 catch 是会按顺序的且匹配 1 个就不再往下匹配,编译器因此识别出 RuntimeExcpetion 永远不会被捕捉到,便提前报错。


Q:throw 异常的时候,在 finally 中做 return,那么异常还会抛出吗?

static int f() {    try {        int a = 1/0;        return a;    } catch (Exception e) {        throw new RuntimeException(e);    } finally {        return -1;    }}public static void main(String[] args) {    System.out.println(f());}
复制代码

A:不会,返回-1.

即 finaly 中做 return 会中断 throw

因此永远不要在 finally 中去做 return 操作

受检异常相关问题


Q: 子类覆写基类方法时 , 能 throws 基类方法中不存在的异常吗?

像下面这样:

class A{    void f() throws IOException{    }}class B extends A{    void f() throws IOException, SQLException {    }}
复制代码

A: 不行,直接编译报错。 即子类覆写父类方法时, throws 关键字后面跟的异常必须是小于等于父类方法异常的。



Q: finally 中调用某资源的 close 时,也会抛出受检异常, 除了在 finally 里做 try-catch,还能怎么做?

像下面这样,finally 又有 catch,就很难看:

TryWithResource tryWithResource = new TryWithResource();        try {            System.out.println(tryWithResource.age);        } catch (Exception e) {            e.printStackTrace();        }finally {            try {                tryWithResource.close();            } catch (Exception e) {                e.printStackTrace();            }        }
复制代码

A:如果是 JDK1.7,可以用 try-with-resource 语法。

需要资源类实现 AutoCloseable 接口, 并在 try 的时候在 try 括号后面跟上资源的创建,如下:

    public static void main(String[] args) {        try (TryWithResource tryWithResource = new TryWithResource()) {            System.out.println(tryWithResource.age);        } catch (Exception e) {            e.printStackTrace();        }    }
复制代码

这样就不需要写 finally,finally+close 会通过编译器给我们自动加上。


Q: 线程抛出异常的话该怎么捕捉?

A: 实现异常处理接口 MyUnchecckedExceptionhandler

public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {    @Override    public void uncaughtException(Thread t, Throwable e) {        System.out.println("捕获异常处理方法:" + e);    }}
复制代码

然后把实现类设置给对应线程。

Thread t = new Thread(new ExceptionThread());t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());t.start();
复制代码


点击关注,第一时间了解华为云新鲜技术~


发布于: 2021 年 03 月 30 日阅读数: 16
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
聊聊Java的异常机制问题