The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
Now that you know what exceptions are and how to use them, it's time to learn the advantages of using exceptions in your programs.现在您已经知道了什么是异常以及如何使用它们,现在是学习在程序中使用异常的优点的时候了。
Exceptions provide the means to separate the details of what to do when something out of the ordinary happens from the main logic of a program.异常提供了一种方法,可以将异常事件发生时的操作细节与程序的主逻辑分开。In traditional programming, error detection, reporting, and handling often lead to confusing spaghetti code.在传统编程中,错误检测、报告和处理通常会导致混乱的意大利面代码。For example, consider the pseudocode method here that reads an entire file into memory.例如,考虑在这里读取整个文件到内存中的伪代码方法。
readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file; }
At first glance, this function seems simple enough, but it ignores all the following potential errors.乍一看,此函数似乎足够简单,但它忽略了以下所有潜在错误。
To handle such cases, the 要处理这种情况,readFile
function must have more code to do error detection, reporting, and handling.readFile
函数必须有更多的代码来执行错误检测、报告和处理。Here is an example of what the function might look like.下面是一个函数的示例。
errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode and -4; } } else { errorCode = -5; } return errorCode; }
There's so much error detection, reporting, and returning here that the original seven lines of code are lost in the clutter.这里有太多的错误检测、报告和返回,原来的七行代码都在混乱中丢失了。Worse yet, the logical flow of the code has also been lost, thus making it difficult to tell whether the code is doing the right thing: Is the file really being closed if the function fails to allocate enough memory?更糟糕的是,代码的逻辑流也丢失了,因此很难判断代码是否做了正确的事情:如果函数未能分配足够的内存,文件是否真的被关闭了?It's even more difficult to ensure that the code continues to do the right thing when you modify the method three months after writing it.在编写方法三个月后修改该方法时,要确保代码继续执行正确的操作就更加困难了。Many programmers solve this problem by simply ignoring it errors are reported when their programs crash.许多程序员通过简单地忽略它来解决这个问题程序崩溃时会报告错误。
Exceptions enable you to write the main flow of your code and to deal with the exceptional cases elsewhere.异常使您能够编写代码的主要流程,并在其他地方处理异常情况。If the 如果readFile
function used exceptions instead of traditional error-management techniques, it would look more like the following.readFile
函数使用异常而不是传统的错误管理技术,那么它看起来更像下面这样。
readFile { try { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } }
Note that exceptions don't spare you the effort of doing the work of detecting, reporting, and handling errors, but they do help you organize the work more effectively.请注意,异常并不会让您省去检测、报告和处理错误的工作,但它们确实可以帮助您更有效地组织工作。
A second advantage of exceptions is the ability to propagate error reporting up the call stack of methods.异常的第二个优点是能够将错误报告传播到方法的调用堆栈中。Suppose that the 假设readFile
method is the fourth method in a series of nested method calls made by the main program: method1
calls method2
, which calls method3
, which finally calls readFile
.readFile
方法是主程序进行的一系列嵌套方法调用中的第四个方法:method1
调用method2
,后者调用method3
,后者最终调用readFile
。
method1 { call method2; } method2 { call method3; } method3 { call readFile; }
Suppose also that 还假设method1
is the only method interested in the errors that might occur within readFile
.method1
是对readFile
中可能发生的错误感兴趣的唯一方法。Traditional error-notification techniques force 传统的错误通知技术强制method2
and method3
to propagate the error codes returned by readFile
up the call stack until the error codes finally reach method1
—the only method that is interested in them.method2
和method3
将readFile
返回的错误代码传播到调用堆栈,直到错误代码最终到达method1
—唯一对它们感兴趣的方法。
method1 { errorCodeType error; error = call method2; if (error) doErrorProcessing; else proceed; } errorCodeType method2 { errorCodeType error; error = call method3; if (error) return error; else proceed; } errorCodeType method3 { errorCodeType error; error = call readFile; if (error) return error; else proceed; }
Recall that the Java runtime environment searches backward through the call stack to find any methods that are interested in handling a particular exception.回想一下,Java运行时环境在调用堆栈中向后搜索,以查找对处理特定异常感兴趣的任何方法。A method can duck any exceptions thrown within it, thereby allowing a method farther up the call stack to catch it.一个方法可以回避它内部抛出的任何异常,从而允许调用堆栈上更远的方法捕获它。Hence, only the methods that care about errors have to worry about detecting errors.因此,只有关心错误的方法才需要担心检测错误。
method1 { try { call method2; } catch (exception e) { doErrorProcessing; } } method2 throws exception { call method3; } method3 throws exception { call readFile; }
However, as the pseudocode shows, ducking an exception requires some effort on the part of the middleman methods.然而,正如伪代码所示,避免异常需要中间人方法的一些努力。Any checked exceptions that can be thrown within a method must be specified in its 必须在方法的throws
clause.throws
子句中指定可以在方法中抛出的任何已检查异常。
Because all exceptions thrown within a program are objects, the grouping or categorizing of exceptions is a natural outcome of the class hierarchy.因为程序中抛出的所有异常都是对象,所以异常的分组或分类是类层次结构的自然结果。An example of a group of related exception classes in the Java platform are those defined in Java平台中一组相关异常类的示例是java.io
IOException
and its descendants.Java.io
中定义的异常类IOException
及其子代。IOException
is the most general and represents any type of error that can occur when performing I/O.IOException
是最通用的,表示执行I/O时可能发生的任何类型的错误。Its descendants represent more specific errors.其子代表示更具体的错误。For example, 例如,FileNotFoundException
means that a file could not be located on disk.FileNotFoundException
意味着无法在磁盘上找到文件。
A method can write specific handlers that can handle a very specific exception.方法可以编写特定的处理程序来处理非常特定的异常。The FileNotFoundException
class has no descendants, so the following handler can handle only one type of exception.FileNotFoundException
类没有子代,因此以下处理程序只能处理一种类型的异常。
catch (FileNotFoundException e) { ... }
A method can catch an exception based on its group or general type by specifying any of the exception's superclasses in the 方法可以通过在catch
statement.catch
语句中指定异常的任何超类,根据异常的组或常规类型捕获异常。For example, to catch all I/O exceptions, regardless of their specific type, an exception handler specifies an 例如,为了捕获所有I/O异常,不管它们的具体类型如何,异常处理程序都会指定一个IOException
argument.IOException
参数。
catch (IOException e) { ... }
This handler will be able to catch all I/O exceptions, including 此处理程序将能够捕获所有I/O异常,包括FileNotFoundException
, EOFException
, and so on.FileNotFoundException
、EOFEException
等。You can find details about what occurred by querying the argument passed to the exception handler.通过查询传递给异常处理程序的参数,可以找到有关发生了什么的详细信息。For example, use the following to print the stack trace.例如,使用以下命令打印堆栈跟踪。
catch (IOException e) { // Output goes to System.err. e.printStackTrace(); // Send trace to stdout. e.printStackTrace(System.out); }
You could even set up an exception handler that handles any 您甚至可以在这里设置一个异常处理程序来处理任何Exception
with the handler here.Exception
。
// A (too) general exception handler catch (Exception e) { ... }
The Exception
class is close to the top of the Throwable
class hierarchy.Exception
类靠近Throwable
类层次结构的顶部。Therefore, this handler will catch many other exceptions in addition to those that the handler is intended to catch.因此,除了处理程序要捕获的异常之外,该处理程序还将捕获许多其他异常。You may want to handle exceptions this way if all you want your program to do, for example, is print out an error message for the user and then exit.例如,如果您只想让程序为用户打印一条错误消息,然后退出,那么您可能希望以这种方式处理异常。
In most situations, however, you want exception handlers to be as specific as possible.然而,在大多数情况下,您希望异常处理程序尽可能具体。The reason is that the first thing a handler must do is determine what type of exception occurred before it can decide on the best recovery strategy.原因是处理程序必须做的第一件事是确定发生了什么类型的异常,然后才能决定最佳恢复策略。In effect, by not catching specific errors, the handler must accommodate any possibility.实际上,通过不捕获特定错误,处理程序必须适应任何可能性。Exception handlers that are too general can make code more error-prone by catching and handling exceptions that weren't anticipated by the programmer and for which the handler was not intended.过于通用的异常处理程序可以捕获和处理程序员没有预料到且处理程序不适用的异常,从而使代码更容易出错。
As noted, you can create groups of exceptions and handle exceptions in a general fashion, or you can use the specific exception type to differentiate exceptions and handle exceptions in an exact fashion.如前所述,您可以创建异常组并以常规方式处理异常,也可以使用特定的异常类型区分异常并以精确的方式处理异常。