Java异常总结

2019-10-13  本文已影响0人  张年轮

目录

理解Throwable、Exception/Error的设计和分类

结构体系

20190225133301229.png

设计原则

常见子类

非检查性异常类:(RuntimeException)

异常 描述
ArithmeticException 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。
ArrayIndexOutOfBoundsException 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
ArrayStoreException 试图将错误类型的对象存储到一个对象数组时抛出的异常。
ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常。
IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
IllegalMonitorStateException 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
IllegalStateException 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
IllegalThreadStateException 线程没有处于请求操作所要求的适当状态时抛出的异常。
IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常
NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
SecurityException 由安全管理器抛出的异常,指示存在安全侵犯。
StringIndexOutOfBoundsException 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。
UnsupportedOperationException 当不支持请求的操作时,抛出该异常。

检查性异常类:(IOException)

异常 描述
ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常。
CloneNotSupportedException 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
IllegalAccessException 拒绝访问一个类的时候,抛出该异常。
InstantiationException 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。
InterruptedException 一个线程被另一个线程中断,抛出该异常。
NoSuchFieldException 请求的变量不存在
NoSuchMethodException 请求的方法不存在

错误(Error)

异常 描述
StackOverflowError 递归过深,递归没有出口。
OutOfMemoryError JVM空间溢出,创建对象速度高于GC回收速度。

自定义异常

除了系统定义的各种"异常"之外,有时候根据程序的需要,开发人员需要定义自己的"异常",也就是"自定义异常"。"自定义异常"有三个原则:

自己定义:"自定义异常"需要继承自Exception类或其子类;
自己抛出:"自定义异常"需要根据情况自己抛出异常对象;
自己处理:需要程序自己来处理"自定义异常情况";
通常来说,自定义异常继承这两个类即可,原则如下:

如果自定义异常继承了 RuntimeException ,处理起来会更简单,但是缺乏了 Exception 类的严谨:
如果在函数内容抛出该异常,函数上不用声明,编译一样通过;
如果在该函数上声明了该异常,调用者可以不用运行处理,编译一样通过

异常处理原则

try-cathc-finally

使用 try 和 catch关键字可以捕获异常,代码块放在异常可能发生的地方。
匹配的原则是:如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。

try-catch体还可以定义一个finally模块,finally模块通常用于资源的回收。
finally体的特点是不论程序有无异常产生都能得到执行,所以我们可以把try块里资源的回收等操作交给它处理(如数据库连接、网络连接和磁盘文件),以便保证其内容一定能得到执行.

注意:只有finally块执行完成之后,才会回来执行try或者catch块中的return或者throw语句,如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止。

throws/throw

如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明,意为抛出异常给父集。但有一点要明白:必须有一级代码需要对异常进行处理,不能一直抛出异常,最终交给JVM处理,因为JVM对检查性异常的处理只有一个方法 – 让系统挂掉。

再说说throw/throws的关系:

try-catch-resources

在JDK7以前,Java没有自动关闭外部资源的语法特性,直到JDK7中新增了try-with-resource语法,才实现了这一功能。

那什么是try-with-resource呢?简而言之,当一个外部资源的句柄对象(比如FileInputStream对象)实现了AutoCloseable接口,那么就可以将上面的板式代码简化为如下形式:

public static void main(String[] args) {
    try (FileInputStream inputStream = new FileInputStream(new File("test"))) {
        System.out.println(inputStream.read());
    } catch (IOException e) {
        throw new RuntimeException(e.getMessage(), e);
    }
}

将外部资源的句柄对象的创建放在try关键字后面的括号中,当这个try-catch代码块执行完毕后,Java会确保外部资源的close方法被调用。

multiple catch

有时当我们调用一段处理时,需要同时捕获多个异常,但是我们对这些异常处理的代码是相同的。比如:

try {
  // do something
} catch (AException e) {
  throw new MyException(e);
} catch (BException e) {
  throw new MyException(e);
}

jdk1.7后可以把上述代码等价地写成:

try {
  // do something
} catch (AException | BException e) {
  throw new MyException(e);
}

java解惑异常规范解析

第57条 只针对异常的情况才使用异常

第58条 对可恢复的情况使用受检异常,对编程错误使用运行时异常

第59条 避免不必要的使用受检的异常
第60条 优先使用标准的异常

第61条 抛出与异常相对于的异常

     public E get(int index) {
         try {
             return listIterator(index).next();
         } catch (NoSuchElementException exc) {
             throw new IndexOutOfBoundsException("Index: "+index);
         }
     }

  

第62条 每个方法抛出的异常都要有文档

第63条 在细节消息中包含能捕获失败的信息
第64条 努力使失败保持原子性

第65条 不要忽略异常

阿里巴巴异常规范解析

  1. 【强制】不要捕获 Java 类库中定义的继承自 RuntimeException 的运行时异常类,如:
    IndexOutOfBoundsException / NullPointerException,这类异常由程序员预检查
    来规避,保证程序健壮性。
    正例:if(obj != null) {...}
    反例:try { obj.method() } catch(NullPointerException e){...}
  2. 【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
  3. 【强制】对大段代码进行 try-catch,这是不负责任的表现。catch 时请分清稳定代码和非稳
    定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的 catch 尽可能进行区分
    异常类型,再做对应的异常处理。
  4. 【强制】捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请
    将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的
    内容。
  5. 【强制】有 try 块放到了事务代码中,catch 异常后,如果需要回滚事务,一定要注意手动回
    滚事务。
  6. 【强制】finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。
    说明:如果 JDK7,可以使用 try-with-resources 方式。
  7. 【强制】不能在 finally 块中使用 return,finally 块中的 return 返回后方法结束执行,不
    会再执行 try 块中的 return 语句。
  8. 【强制】捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。
    说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。
  9. 【推荐】方法的返回值可以为 null,不强制返回空集合,或者空对象等,必须添加注释充分
    说明什么情况下会返回 null 值。调用方需要进行 null 判断防止 NPE 问题。
    说明:本规约明确防止 NPE 是调用者的责任。即使被调用方法返回空集合或者空对象,对调用
    者来说,也并非高枕无忧,必须考虑到远程调用失败,运行时异常等场景返回 null 的情况。
  10. 【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:
    1) 返回类型为包装数据类型,有可能是 null,返回 int 值时注意判空。
    反例:public int f(){ return Integer 对象}; 如果为 null,自动解箱抛 NPE。 2) 数据库的查询结果可能为 null。 3) 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。
    阿里巴巴 Java 开发手册
    ——禁止用于商业用途,违者必究—— 20 / 34
    4) 远程调用返回对象,一律要求进行 NPE 判断。
    5) 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。
    6) 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。
  11. 【推荐】在代码中使用“抛异常”还是“返回错误码”,对于公司外的 http/api 开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间 RPC调用优先考虑使用 Result 方式,封装 isSuccess、“错误码”、“错误简短信息”。
    说明:关于 RPC 方法返回方式使用 Result 方式的理由:
    1)使用抛异常返回方式,调用方如果没有捕获到就会产生运行时错误。
    2)如果不加栈信息,只是 new 自定义异常,加入自己的理解的 error message,对于调用端解决问题的帮助不会太多。如果加了栈信息,在频繁调用出错的情况下,数据序列化和传输的性能损耗也是问题。
  12. 【推荐】定义时区分 unchecked / checked 异常,避免直接使用 RuntimeException 抛出,
    更不允许抛出 Exception 或者 Throwable,应使用有业务含义的自定义异常。推荐业界已定义
    过的自定义异常,如:DAOException / ServiceException 等。
  13. 【参考】避免出现重复的代码(Don’t Repeat Yourself),即 DRY 原则。
    说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副
    本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是共用模块。
    正例:一个类中有多个 public 方法,都需要进行数行相同的参数校验操作,这个时候请抽取:
    private boolean checkParam(DTO dto){...}

常见面试问题

java中内存溢出和内存泄漏的区别

虽然在java中我们不用关心内存的释放,垃圾回收机制帮助我们回收不需要的对象,但实际上不正当的操作也会产生内存问题:如,内存溢出、内存泄漏。

NoClassDefFoundError和ClassNotFoundException的区别

资料

上一篇 下一篇

猜你喜欢

热点阅读