让异常向上移动调用堆栈的价值是什么?
What is the value of letting an exception move up the call stack?
我只是 reading about try-catch blocks
和异常处理,我在 "Propagating IOExceptions" 部分读到一些让我有点困惑的东西。 Jenkov 说,如果方法 C 抛出 IOException
- public void MethC() throws IOException{}
- 但没有 try-catch
来处理它,它会将调用堆栈汇总到可能具有 try-catch
处理异常
try-catch-finally
块的全部意义似乎是处理异常,如果不处理,程序就会崩溃,对吗?好吧,那为什么要让异常回滚调用堆栈到链上某处的 try-catch
呢?价值是多少?如果有的话,在我看来,让异常在链条上滚动,而不是立即处理它只会危及程序,并且形式不佳,导致效率低下或效率低下。
只要您的设计有意让异常渗透到调用堆栈中就完全没有问题。一个简单的示例是,如果您的 main
方法在调用周围有一个 try
/catch
块,该调用可能具有非常深的调用堆栈。如果在任何时候发生错误,它可以 throw
一个异常并且程序可以优雅地结束 catch
in main
说 "Sorry, the following excpetion happened, so the program is ending".
从不捕获异常并让程序异常终止将是糟糕的设计,但是如果在实例中有意义的话,从实际异常发生的地方捕获它并没有错。
问题常常发生在代码深处,正确的处理方式(显示对话框?打印错误?安静地处理?)可能因不同的调用路径而有所不同,选择做什么可以在调用堆栈的其他地方进行。
一般情况下,异常应该在调用栈中能够处理的地方处理。
例如,假设您有一个库方法,它采用文件路径和 returns 文件的全部内容,如 byte[]
:
public static byte[] readFile(final String filePath) throws IOException {
final InputStream inputStream = new FileInputStream(filePath);
...
}
这个函数不可能"handle"一个不存在的文件;如果 new FileInputStream(filePath)
引发一个 FileNotFoundException
(它是 IOException
的子类型),那么这个函数能做的最好的事情就是通知它的调用者。调用者有更多关于 filePath
来源的信息,以及文件丢失意味着什么;例如,如果 filePath
是由用户输入的,那么这可能意味着程序需要向用户显示一条消息,让 him/her 知道可能存在错字。关键是,readFile
没有任何这些信息,无法做出正确的决定。所以它应该让异常传播到可以传播的调用者。
有时让异常回滚堆栈会有帮助,原因有很多(服务、Restfull api 等)。假设您有一个显示或解析文件并将文件名作为参数的方法,您不知道谁将使用您的方法或用于什么目的,因此通过抛出异常,您给了开发人员另一个显示他的消息或句柄的机会如他所愿。
The whole point of a try-catch-finally
block seems to be to handle an exception that would, unhandled, crash your program right?
不完全是。异常并不总是导致程序崩溃,它可能 "just" 导致程序的某些部分无法正常工作。确实try-catch-finally
是用来处理异常的
Why let the exception roll back up the call stack to a try-catch somewhere up the chain? What is the value?
因为有时发生异常的方法不适合决定如何处理它。
我举个例子:看看方法Integer.parseInt(String s)
,它接受一个String
并尝试根据它的内容将它转换成一个int
。由于这是在运行时完成的,并且您无法提前知道字符串是什么,因此您必须考虑该字符串不会是一个数字,比如说,如果它来自用户输入。如果它不是可解析的字符串,您希望该方法如何处理它?为什么要由它来决定它并非旨在执行的操作的结果?
这就是该方法抛出 NumberFormatException - if the string does not contain a parsable integer
的原因。调用该方法的人有权决定应该做什么,因为该方法专用于将字符串转换为数字。它可以要求一个新的字符串,因为最后一个字符串无效,或者只使用默认数字作为一种占位符。
一个现实生活中的类比:老板告诉他的秘书安排在给定日期与一名员工会面,秘书发现该员工在该日期休假。秘书应该自己处理吗?可能不会。相反,他们会 "throw an exception" 按照 "InvalidMeetingTime" 的方式告诉他们的老板,让老板决定做什么。
It seems to me that letting the exception roll up the chain, instead of handling it right away would just compromise the program and be bad form and cause inefficiencies or be inefficient.
这就是调用范围负责正确委托事件的原因。要么自己处理它,要么向上传递,直到有人处理它。
在 Lesson: Exceptions 查看更多信息。
我只是 reading about try-catch blocks
和异常处理,我在 "Propagating IOExceptions" 部分读到一些让我有点困惑的东西。 Jenkov 说,如果方法 C 抛出 IOException
- public void MethC() throws IOException{}
- 但没有 try-catch
来处理它,它会将调用堆栈汇总到可能具有 try-catch
处理异常
try-catch-finally
块的全部意义似乎是处理异常,如果不处理,程序就会崩溃,对吗?好吧,那为什么要让异常回滚调用堆栈到链上某处的 try-catch
呢?价值是多少?如果有的话,在我看来,让异常在链条上滚动,而不是立即处理它只会危及程序,并且形式不佳,导致效率低下或效率低下。
只要您的设计有意让异常渗透到调用堆栈中就完全没有问题。一个简单的示例是,如果您的 main
方法在调用周围有一个 try
/catch
块,该调用可能具有非常深的调用堆栈。如果在任何时候发生错误,它可以 throw
一个异常并且程序可以优雅地结束 catch
in main
说 "Sorry, the following excpetion happened, so the program is ending".
从不捕获异常并让程序异常终止将是糟糕的设计,但是如果在实例中有意义的话,从实际异常发生的地方捕获它并没有错。
问题常常发生在代码深处,正确的处理方式(显示对话框?打印错误?安静地处理?)可能因不同的调用路径而有所不同,选择做什么可以在调用堆栈的其他地方进行。
一般情况下,异常应该在调用栈中能够处理的地方处理。
例如,假设您有一个库方法,它采用文件路径和 returns 文件的全部内容,如 byte[]
:
public static byte[] readFile(final String filePath) throws IOException {
final InputStream inputStream = new FileInputStream(filePath);
...
}
这个函数不可能"handle"一个不存在的文件;如果 new FileInputStream(filePath)
引发一个 FileNotFoundException
(它是 IOException
的子类型),那么这个函数能做的最好的事情就是通知它的调用者。调用者有更多关于 filePath
来源的信息,以及文件丢失意味着什么;例如,如果 filePath
是由用户输入的,那么这可能意味着程序需要向用户显示一条消息,让 him/her 知道可能存在错字。关键是,readFile
没有任何这些信息,无法做出正确的决定。所以它应该让异常传播到可以传播的调用者。
有时让异常回滚堆栈会有帮助,原因有很多(服务、Restfull api 等)。假设您有一个显示或解析文件并将文件名作为参数的方法,您不知道谁将使用您的方法或用于什么目的,因此通过抛出异常,您给了开发人员另一个显示他的消息或句柄的机会如他所愿。
The whole point of a
try-catch-finally
block seems to be to handle an exception that would, unhandled, crash your program right?
不完全是。异常并不总是导致程序崩溃,它可能 "just" 导致程序的某些部分无法正常工作。确实try-catch-finally
是用来处理异常的
Why let the exception roll back up the call stack to a try-catch somewhere up the chain? What is the value?
因为有时发生异常的方法不适合决定如何处理它。
我举个例子:看看方法Integer.parseInt(String s)
,它接受一个String
并尝试根据它的内容将它转换成一个int
。由于这是在运行时完成的,并且您无法提前知道字符串是什么,因此您必须考虑该字符串不会是一个数字,比如说,如果它来自用户输入。如果它不是可解析的字符串,您希望该方法如何处理它?为什么要由它来决定它并非旨在执行的操作的结果?
这就是该方法抛出 NumberFormatException - if the string does not contain a parsable integer
的原因。调用该方法的人有权决定应该做什么,因为该方法专用于将字符串转换为数字。它可以要求一个新的字符串,因为最后一个字符串无效,或者只使用默认数字作为一种占位符。
一个现实生活中的类比:老板告诉他的秘书安排在给定日期与一名员工会面,秘书发现该员工在该日期休假。秘书应该自己处理吗?可能不会。相反,他们会 "throw an exception" 按照 "InvalidMeetingTime" 的方式告诉他们的老板,让老板决定做什么。
It seems to me that letting the exception roll up the chain, instead of handling it right away would just compromise the program and be bad form and cause inefficiencies or be inefficient.
这就是调用范围负责正确委托事件的原因。要么自己处理它,要么向上传递,直到有人处理它。
在 Lesson: Exceptions 查看更多信息。