以往面试的时候问Java异常好像背一背题就行,但是这个面试官水平还是很高的,换了一种问法,大概是这么问的:
Java中写了一个函数,打开了一个文件,读这个文件然后关闭,中间没有写try-catch,保存之后,编辑器自动在这个函数声明后面加了throws exception,你觉得这些exception会有哪些呢?
如果把这个函数进行修改,不读写文件,只进行简单的数据处理,这时保存之后,发现函数声明的后面没有throws这些异常了,在这种情况下是不是就不会抛出异常了?
有点懵了,完犊子。。。
主要有以下几点,掌握了应该问题不大:
文件操作的异常主要是IOException及其子类,属于受检异常,必须显式处理(要么 try-catch,要么 throws);
简单数据处理的异常多是RuntimeException 及其子类(如空指针、数组越界),属于非受检异常,无需强制 throws 或 try-catch;
受检异常要求“编译时必须处理”,非受检异常是“运行时才可能出现”,编辑器不强制要求。
文件操作会抛出哪些异常?
复现一下面试题里的场景:
写了一个文件读写函数,没加 try-catch,编辑器自动加了 throws Exception。
import java.io.*;publicclassFileReadExample{// 编辑器自动加了 throws Exception,因为里面有受检异常publicvoidreadFile(String filePath)throws Exception {// 1. 打开文件流 FileInputStream fis = new FileInputStream(filePath);// 2. 读取文件内容byte[] buffer = newbyte[1024];int len = fis.read(buffer);// 3. 关闭文件流 fis.close(); }}有以下几种文件操作中常见的异常
小贴士:
FileNotFoundException 是 IOException 的子类,如果 throws IOException,也能覆盖 FileNotFoundException。
为什么简单数据处理不需要 throws?
面试题里的第二个场景:
把函数改成只做简单数据处理,编辑器就不加 throws 了。
复现一下这个场景:
publicclassSimpleDataProcessExample{// 编辑器不会加 throws,因为里面都是非受检异常publicvoidprocessData(int[] arr, String str){// 1. 数组越界:ArrayIndexOutOfBoundsException(非受检)int num = arr[10];// 2. 空指针:NullPointerException(非受检)int len = str.length();// 3. 非法参数:IllegalArgumentException(非受检)if (arr.length == 0) {thrownew IllegalArgumentException("数组不能为空"); } }}这里的主要原因是:
简单数据处理的异常都是 RuntimeException 的子类,是非受检异常,编辑器不会强制要求 throws 或 try-catch。
受检异常 vs 非受检异常
ExceptionRuntimeException 及其子类) | RuntimeExceptionError 及其子类 | |
IOExceptionFileNotFoundException | NullPointerExceptionArrayIndexOutOfBoundsException、IllegalArgumentException | |
try-catch 或 throws | ||
实际开发中,文件操作的异常怎么处理?
不要直接 throws Exception,推荐显式抛出具体异常(如 throws IOException)或者 try-catch 处理,记录日志并给出友好提示。
举个例子:
publicvoidreadFile(String filePath){ FileInputStream fis = null;try { fis = new FileInputStream(filePath);byte[] buffer = newbyte[1024];int len = fis.read(buffer); } catch (FileNotFoundException e) { System.err.println("文件不存在:" + filePath); e.printStackTrace(); } catch (IOException e) { System.err.println("文件读取失败"); e.printStackTrace(); } finally {// 必须在 finally 里关闭流,防止内存泄漏if (fis != null) {try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } }}