跳至主要內容

Java异常

小熊同学大约 6 分钟

1、Java 中异常分为哪些种类?

按照异常需要处理的时机分为编译时异常(也叫强制性异常)也叫 CheckedException运行时异常(也叫非强制性异常)也叫 RuntimeException

只有 java 语言提供了 Checked 异常,Java 认为 Checked异常都是可以被处理的异常,所以 Java 程序必须显式处理 Checked 异常。如果程序没有处理 Checked 异常,该程序在编译时就会发生错误无法编译。这体现了 Java 的设计哲学:没有完善错误处理的代码根本没有机会被执行。

对 Checked 异常处理方法有两种:

  1. 当前方法知道如何处理该异常,则用 try...catch 块来处理该异常。
  2. 当前方法不知道如何处理,则在定义该方法是声明抛出该异常。

运行时异常只有当代码在运行时才发行的异常,编译时不需要 try catch。Runtime 如除数是 0 和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。

2、调用下面的方法,得到的返回值是什么?

public int getNum(){
    try{
       int i = 10 / 0;
        return 1;
    }catch(Exception e){
        return 2;
	}finally{
        return 3;
    }
}

分析

  1. 代码走到第3行的时候,遇到了一个 MathException,因此第4行不会执行了,代码跳到catch里面
  2. 代码走到第6行的时候,异常机制有这么一个原则:如果在 catch 中遇到了 return 或者异常等能使该函数终止的话,那么有 finally 就必须先执行完 finally 代码块里面的代码,然后再返回值。因此跳到第8行。
  3. 第8行是一个return语句,这个时候就结束了,第6行的值无法被返回。返回值为3.
  4. 若第8行不是一个return语句,而是一个释放资源的操作,则返回值为2.

3、Error 和 Exception 区别是什么?

  • Error 类型的错误通常为虚拟机相关错误,如系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,JAVA 应用程序也不应对这类错误进行捕获,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复;
  • Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。

4、运行时异常和一般异常(受检异常)区别是什么?

  • 运行时异常包括 RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。 Java 编译器不会检查运行时异常。
  • 检异常是Exception 中除 RuntimeException 及其子类之外的异常。 Java 编译器会检查受检异常。
  • RuntimeException异常和受检异常之间的区别:是否强制要求调用者必须处理此异常,如果强制要求调用者必须进行处理,那么就使用受检异常,否则就选择非受检异常(RuntimeException)。
  • 一般来讲,如果没有特殊的要求,我们建议使用RuntimeException异常。

5、throw 和 throws 的区别是什么?

throw:

  • throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
  • throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常。

throws:

  • throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
  • throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
  • throws 表示出现异常的一种可能性,并不一定会发生这种异常。

6、final、finally、finalize 的区别?

final:可用于修饰属性、方法、类。修饰的属性不可变(不能重新被赋值),方法不能重写,类不能继承。

finally:异常处理语句try-catch的一部分,一般将一定要执行的代码放在finally代码块中,总是被执行,一般用来存放一些关闭资源的操作。

finalize:Object 类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。该方法更像是一个对象生命周期的临终方法,当该方法被系统调用则代表该对象即将“死亡”,但是需要注意的是,我们主动行为上去调用该方法并不会导致该对象“死亡”,这是一个被动的方法(其实就是回调方法),不需要我们调用。

7、常见的 RuntimeException 有哪些?

  • ClassCastException:数据类型转换异常
  • IndexOutOfBoundsException:数组下标越界异常,常见于操作数组对象时发生。
  • NullPointerException:空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
  • ClassNotFoundException:指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。
  • NumberFormatException:字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
  • IllegalArgumentException:方法传递参数异常
  • NoClassDefFoundException:未找到定义类异常
  • SQLException SQL:常见于操作数据库时的 SQL 语句错误。
  • InstantiationException:实例化异常。
  • NoSuchMethodException:方法不存在异常
  • ArrayStoreException:数据存储异常,操作数组时类型不一致
  • 还有IO操作的BufferOverflowException异常

8、finally内存回收的情况?

  1. 如果在try... catch 部分用Connection 对象连接了数据库,而且在后继部台不会再用到这个连接对象,那么一定要在 finally从句中关闭该连接对象, 否则该连接对象所占用的内存资源无法被回收。
  2. 如果在try... catch 部分用到了一些IO对象进行了读写操作,那么也一定要在finally 中关闭这些IO对象,否则,IO对象所占用的内存资源无法被回收。
  3. 如果在try .catch 部分用到了ArrayList 、Linkedlist 、Hash Map 等集合对象,而且这些对象之后不会再被用到,那么在finally中建议通过调用clear方法来清空这些集合。
  4. 例如,在try .catch 语句中育一个对象obj 指向7一块比较大的内存空间(假设100MB) ,而且之后不会再被用到,那么在 finally 从句中建议写上 obj=null,这样能提升内存使用效率。

9、异常的设计原则有哪些?

  • 不要将异常处理用于正常的控制流
  • 对可以恢复的情况使用受检异常,对编程错误使用运行时异常
  • 避免不必要的使用受检异常
  • 优先使用标准的异常
  • 每个方法抛出的异常都要有文档
  • 保持异常的原子性
  • 不要在 catch 中忽略掉捕获到的异常