目录
面试题一:请介绍 Java 的异常接口
「Throwable」是异常的顶层父类,代表所有的非正常情况。它有两个直接子类,分别是「Error」「Exception」。
Error 是错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用 catch 块来捕获Error 对象。在定义方法时,也无须在其 throws 子句中声明该方法可能抛出 Error 及其任何子类。
Exception 是异常,它被分为两大类,分别是 Checked 异常和 Runtime 异常。所有的 RuntimeException 类及其子类的实例被称为 Runtime 异常;不是 RuntimeException 类及其子类的异常实例则被称为 Checked 异常。Java 认为 Checked 异常都是可以被处理(修复)的异常,所以 Java 程序必须显式处理 Checked 异常。如果程序没有处理 Checked 异常,该程序在编译时就会发生错误,无法通过编译。Runtime 异常则更加灵活,Runtime 异常无须显式声明抛出,如果程序需要捕获 Runtime 异常,也可以使用 try…catch 块来实现。
追问一:Error 和 Exception 的区别?
Error 类和 Exception 类的父类都是 Throwable 类。
主要区别如下:
Error 类: ⼀般是指与虚拟机相关的问题,如:系统崩溃、虚拟机错误、内存空间不足、方法调用栈溢出等。这类错误将会导致应用程序中断,仅靠程序本身无法恢复和预防;
Exception 类:Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。分为运行时异常和受检查的异常。
追问二:运行时异常与受检异常有何异同?
- 运行时异常:如:空指针异常、指定的类找不到、数组越界、方法传递参数错误、数据类型转换错误。可以编译通过,但是⼀运行就停止了,程序不会自己处理;
- 受检查异常:要么用 try … catch… 捕获,要么用 throws 声明抛出,交给父类处理。
追问三: throw 和 throws 的区别?
- throw:在方法体内部,表示抛出异常,由方法体内部的语句处理,跟的是异常对象名;throw 是具体向外抛出异常的动作,所以它抛出的是⼀个异常实例;
- throws:在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理;表示出现异常的可能性,并不⼀定会发生这种异常。throws可以抛出多个异常。
面试题二: 常见的异常类有哪些?
NullPointerException:当应用程序试图访问空对象时,则抛出该异常。
SQLException:提供关于数据库访问错误或其他错误信息的异常。
IndexOutOfBoundsException:指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
FileNotFoundException:当试图打开指定路径名表示的⽂件失败时,抛出此异常。
IOException:当发生某种 I/O 异常时,抛出此异常。此类是失败或中断的 I/O 操作生成的异常的通用类。
ClassCastException:当试图将对象强制转换为不是实例的⼦类时,抛出该异常。
IllegalArgumentException:抛出的异常表明向⽅法传递了⼀个不合法或不正确的参数。
追问一:NoClassDefFoundError 和 ClassNotFoundException 区别?
- NoClassDefFoundError 是一种 Error,Error 在大多数情况下代表无法从程序中恢复的致命错误,产生的原因在于 JVM 或者 ClassLoader 在运行时类加载器在 classpath 下找不到需要的类定义(编译期是可以正常找到的,所以和 ClassNotFoundException 不同的是这是一个运行期的 Error),这个时候虚拟机就会抛出 NoClassDefFoundError,通常造成该 ERROR 的原因是打包过程中漏掉了部分类,或者 jar 包出现损坏或篡改,对应的 Class 在 classpath 中不可用等等原因。
- ClassNotFoundException 是属于 Exception 的运行时异常,大多是可以从代码中恢复的异常类型,导致该异常的原因大多是因为使用 Class.forName() 方法动态的加载类信息,但是这个类在类路径中并没有被找到,那么就会在运行时抛出 ClassNotFoundException。
面试题三:主线程可以捕获到子线程的异常吗?
线程设计的理念:“线程的问题应该线程自己本身来解决,而不要委托到外部”。正常情况下,如果不做特殊的处理,在主线程中是不能够捕获到子线程中的异常的。
如果想要在主线程中捕获子线程的异常,我们可以用如下的方式进行处理,使用 Thread 的静态方法。
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandle());