我刚刚阅读了有关try-catch blocks
和异常处理的内容,我在"传播IOExceptions"部分中读到了一些让我有点困惑的内容。Jenkov 说,如果方法 C 抛出一个IOException
-public void MethC() throws IOException{}
- 但没有处理它的try-catch
,它将调用堆栈汇总到一个调用方法,该方法可能具有处理异常try-catch
。try-catch-finally
块的重点似乎是处理一个异常,如果不处理,你的程序会崩溃,对吗?那么,为什么要让异常将调用堆栈回滚到链上某处的try-catch
呢?价值是什么?如果有的话,在我看来,让异常卷起链,而不是立即处理它只会损害程序并且形式不佳并导致效率低下或效率低下。
try-catch-finally
块的全部意义似乎是处理一个异常,如果不处理,会使你的程序崩溃,对吗?
不完全是。异常并不总是导致程序崩溃,它可能"只是"导致它的某些部分无法正常工作。确实,try-catch-finally
用于处理异常。
为什么要让异常将调用堆栈回滚到链上某处的 try-catch?价值是什么?
因为有时发生异常的方法不适合决定如何处理它。
我举个例子:看方法Integer.parseInt(String s)
,它需要一个String
,并尝试根据其内容将其转换为int
。由于这是在运行时完成的,并且您无法提前知道字符串是什么,因此您必须考虑字符串将不是一个数字,例如,如果它来自用户输入。如果它不是可解析的字符串,您希望该方法如何处理它?为什么它应该决定它不是设计要执行的操作的结果?
这就是为什么该方法抛出NumberFormatException - if the string does not contain a parsable integer
。调用该方法的人都可以决定应该做什么,因为该方法仅用于将字符串转换为数字。它可以请求一个新字符串,因为最后一个字符串无效,或者只是使用默认数字作为占位符。
一个现实生活中的类比:老板告诉他的秘书安排与员工会面 en 在给定的日期,秘书发现该员工在该日期休假。秘书应该自己处理吗?应该不会。相反,他们会按照"无效会议时间"的思路向老板"抛出一个例外",让老板决定该怎么做。
在我看来,让异常卷起链条,而不是立即处理它只会损害程序并且形式不佳,导致效率低下或效率低下。
这就是为什么调用范围负责正确委派事件的原因。要么自己处理它,要么向上传递它,直到有东西处理它。
有关详细信息,请参阅课程:例外。
只要您的设计有意,让异常渗透到调用堆栈中是完全可以的。 一个简单的示例是,如果您的main
方法在可以具有非常深的调用堆栈的调用周围有一个try
/catch
块。如果在任何时候发生错误,它可以throw
异常,程序可以优雅地结束,catch
main
说"对不起,发生了以下排除,所以程序正在结束"。
从不捕获异常并让程序异常终止将是糟糕的设计,但如果在实例中有意义,那么从实际异常发生的位置捕获它很多级别并没有错。
通常,问题发生在代码的深处,处理它的正确方法(显示对话框、打印错误、悄悄处理它?)可能通过不同的调用路径而有所不同,并且可以选择在调用堆栈中的其他地方执行操作。
通常,应在调用堆栈中能够处理异常的位置处理异常。
例如,假设您有一个库方法,该方法采用文件路径并返回文件的全部内容,作为byte[]
:
public static byte[] readFile(final String filePath) throws IOException {
final InputStream inputStream = new FileInputStream(filePath);
...
}
这个函数不可能"处理"一个不存在的文件;如果new FileInputStream(filePath)
引发一个FileNotFoundException
(这是IOException
的子类型),那么这个函数能做的最好的事情就是通知它的调用者。调用方具有有关filePath
来自何处以及文件丢失意味着什么的更多信息;例如,如果filePath
是由用户输入的,那么这可能意味着程序需要向用户显示一条消息,让他/她知道可能的拼写错误。关键是,readFile
没有任何这些信息,也无法做出正确的决定。因此,它应该让异常传播到可以的调用方。
有时,出于多种原因(Service、Restfull api 等),让异常回滚堆栈会很有帮助。假设您有一个显示或解析文件并将文件名作为参数的方法,您不知道谁将使用您的方法或出于什么目的,因此通过抛出异常,您给了开发人员另一个机会来显示他的消息或按照他的意愿处理它。