简体   繁体   English

Java 中已检查与未检查的异常

[英]Checked vs Unchecked Exceptions in Java

I am having some problems with understanding the differences between checked and unchecked exceptions in Java.我在理解 Java 中已checkedunchecked异常之间的差异时遇到了一些问题。

  1. Firstly, checked exceptions are supposed to look for abnormalities during compile time.首先, checked异常应该在编译时寻找异常。 Examples provided in different sources cite database connectivity, file handling as some of them, while unchecked exceptions are supposed to look for errors on the programmer's part, like indexing beyond the range of an array, etc.不同来源中提供的示例引用了数据库连接、文件处理作为其中的一些,而unchecked异常应该寻找程序员方面的错误,例如索引超出数组范围等。

Shouldn't it be the other way round?不应该反过来吗? I mean, database connectivity is done during run-time, right?我的意思是,数据库连接是在运行时完成的,对吗? Same goes for file-handling.文件处理也是如此。 You don't open a file-handle during compile time, so why a possible error on that is looked for during compile-time?您在编译期间不打开文件句柄,那么为什么在编译期间查找可能的错误呢? On the other hand, indexing an array beyond its range is already done in the program, which can be checked during compile time (if the abnormal index is supplied by user during run-time, then it's okay for it to be a run-time problem).另一方面,对超出范围的数组进行索引已经在程序中完成,可以在编译时检查(如果异常索引是用户在运行时提供的,那么它是一个运行时也可以)问题)。 What am I missing here?我在这里缺少什么?

2 Secondly, how can RunTimeException , itself being unchecked , subclass Exception , which is checked ? 2 其次, RunTimeException本身如何uncheckedunchecked ,子类Exceptionchecked What does this signify?这意味着什么?

I found an example in Herbert Schildt's book explaining the usage of checked exceptions:我在 Herbert Schildt 的书中找到了一个例子,解释了checked异常的用法:

class ThrowsDemo {
   public static char prompt(String str)
      throws java.io.IOException {
  System.out.print(str + ": ");
  return (char) System.in.read();
  }
  public static void main(String args[]) {
    char ch;
    try {
      ch = prompt("Enter a letter");
    }
    catch(java.io.IOException exc) {
     System.out.println("I/O exception occurred.");
     ch = 'X';
    }
    System.out.println("You pressed " + ch);
    }
}

Is the throws clause necessary here?这里是否需要throws子句? Why can't I do it just normally with a try-catch statement like this (sorry I don't know how to simulate an IO Exception , so couldn't check it myself!):为什么我不能用像这样的try-catch语句正常地做到这一点(对不起,我不知道如何模拟IO Exception ,所以无法自己检查!):

class ThrowsDemo {
   public static char prompt(String str)  {
     System.out.print(str + ": ");
     return (char) System.in.read();
  }
  public static void main(String args[]) {
    char ch;
    try {
      ch = prompt("Enter a letter");
    }
    catch(java.io.IOException exc) {
     System.out.println("I/O exception occurred.");
     ch = 'X';
    }
    System.out.println("You pressed " + ch);
    }
}

CheckedException needs to be handled by the caller, Unchecked exception don't. CheckedException 需要由调用者处理,Unchecked 异常不需要。

So, when you design your application you should take in mind what kind of exceptional situation you are managing.所以,当你设计你的应用程序时,你应该记住你正在管理什么样的特殊情况。

For example, if you design a validation method that checks the validity of some user input, then you know that the caller must check the validation exception and display the errors to the user in a nice looking way.例如,如果您设计了一个验证方法来检查某些用户输入的有效性,那么您知道调用者必须检查验证异常并以美观的方式向用户显示错误。 This should be a checked exception.这应该是一个已检查的异常。

Or, for those exceptional conditions that can be recovered: imagine you have a load balancer and you want notify the caller that one of the "n" servers is down, so the caller must recover the incident re-routing the message to another server;或者,对于那些可以恢复的异常情况:假设您有一个负载平衡器,并且您想通知调用方“n”个服务器中的一个已关闭,因此调用方必须恢复事件并将消息重新路由到另一台服务器; this should be a checked exception, because it is crucial that the caller (client) tries to recover the error, and don't just let the error to break the program flow.这应该是一个已检查的异常,因为调用者(客户端)尝试恢复错误至关重要,而不要让错误破坏程序流程。

Instead, there are many conditions that should not happen, and/or should instead break the program.相反,有许多情况不应该发生,和/或应该破坏程序。 For example, a programming error (like division by zero, null pointer exception), a wrong usage of an API (IllegalStateException, OperationNotSupportedException), an hardware crash, or just some minor situation that are not recoverable (lost connection to a server), or a doomsday :-) ;例如,编程错误(如被零除、空指针异常)、API 的错误使用(IllegalStateException、OperationNotSupportedException)、硬件崩溃或一些无法恢复的小情况(与服务器的连接丢失),或世界末日:-); in those cases, the normal handling is to let the exception reach the most outer block of your code that displays to the user that an unpredictable error has occurred and the application can't do nothing to continue.在这些情况下,正常处理是让异常到达代码的最外层块,该块向用户显示发生了不可预测的错误并且应用程序无法继续执行任何操作。 It's aa fatal condition, so the only thing you can do is to print it to the logs or showing it to the user in the user interface.这是一种致命的情况,因此您唯一能做的就是将其打印到日志中或在用户界面中向用户显示。 In those cases, catching the exception is wrong, because, after catching the exception you need to manually stop the program to avoid further damages;在这些情况下,捕获异常是错误的,因为捕获异常后您需要手动停止程序以避免进一步损坏; so it could be better to let some kind of exception "hit the fan" :)所以最好让某种异常“击中风扇”:)

For those reasons there are some exceptions that are Unchecked also in the JRE: OutOfMemoryError (unrecoverable), NullPointerException (it's a bug that needs to be fixed), ArrayIndexOutOfBoundsException (another bug example), and so on.由于这些原因,JRE 中还有一些未检查的异常:OutOfMemoryError(不可恢复)、NullPointerException(这是一个需要修复的错误)、ArrayIndexOutOfBoundsException(另一个错误示例)等等。

I personally think that also SQLException should be unchecked, since it denotes a bug in the program, or a connection problem to the database.我个人认为 SQLException 也应该取消检查,因为它表示程序中的错误,或者与数据库的连接问题。 But there are many examples where you get exception that you really don't have any clue in how to manage (RemoteException).但是有很多例子你会得到异常,你真的不知道如何管理(RemoteException)。

The best way to handle exceptions are: if you can recover or manage the exception, handle it.处理异常的最好方法是:如果你能恢复或管理异常,就处理它。 Otherwise let the exception pass out;否则让异常通过; somebody else will need to handle.其他人将需要处理。 If you are the last "somebody else" and you don't know how to handle an exception, just display it (log or display in the UI).如果您是最后一个“其他人”并且您不知道如何处理异常,只需显示它(在 UI 中记录或显示)。

  1. you do not need to declare unchecked exceptions in a throws clause;您不需要在throws子句中声明未经检查的异常; but you must declare checked exceptions;但你必须声明受检异常;
  2. RuntimeException and Error , and all of their subclasses ( IllegalArgumentException , StackOverflowError etc), are unckecked exceptions; RuntimeExceptionError ,以及它们的所有子类( IllegalArgumentExceptionStackOverflowError等),都是 unckecked 异常; the fact that RuntimeException is unchecked, unlike other Throwable subclasses, is by design;与其他Throwable子类不同, RuntimeException是未经检查的,这是设计Throwable
  3. there is no such thing as "compile time exceptions".没有“编译时异常”这样的东西。

More generally, it is considered that unchecked exceptions are thrown in the event of either JVM errors or programmer errors.更一般地,认为在 JVM 错误或程序员错误的情况下会抛出未经检查的异常。 One famous such exception is NullPointerException , often abbreviated as NPE, which is a subclass of RuntimeException , and therefore unchecked.一个著名的此类异常是NullPointerException ,通常缩写为 NPE,它是RuntimeException的子类,因此未经检查。

Another very crucial difference between unchecked exceptions and checked exceptions is that within a try-catch block, if you want to catch unchecked exceptions, you must catch them explicitly .未检查异常和已检查异常之间的另一个非常重要的区别是,在 try-catch 块中,如果要捕获未检查异常,则必须明确地捕获它们

Final note: if you have exception classes E1 and E2 and E2 extends E1 , then catching and/or throwing E1 also catches/throws E2 .最后一点:如果您有异常类E1E2并且E2扩展E1 ,那么捕获和/或抛出E1也会捕获/抛出E2 This stands for both checked and unchecked exceptions.这代表已检查和未检查的异常。 This has an implication on catch blocks: if you do differentiate between catching E2 and E1 , you must catch E2 first.这对catch块有一个含义:如果您确实区分了捕获E2E1 ,则必须先捕获E2

For instance:例如:

// IllegalArgumentException is unchecked, no need to declare it
public void illegal()
{
    throw new IllegalArgumentException("meh");
}

// IOException is a checked exception, it must be declared
public void ioerror()
    throws IOException
{
    throw new IOException("meh");
}

// Sample code using illegal(): if you want to catch IllegalArgumentException,
// you must do so explicitly. Not catching it is not considered an error
public void f()
{
    try {
        illegal();
    } catch (IllegalArgumentException e) { // Explicit catch!
        doSomething();
    }
}

I hope this makes things clearer...我希望这能让事情更清楚......

  1. No. All the exceptions happen at runtime.不。所有异常都发生在运行时。 Checked exceptions are exceptions that force the caller to handle them or declare them.受检异常是强制调用者处理或声明它们的异常。 They are usually intended to signal recoverable errors, which are not caused by a programmer error (like a file not being there, or a network connectivity problem).它们通常用于指示可恢复的错误,这些错误不是由程序员错误引起的(例如文件不存在,或网络连接问题)。 Runtime exceptions are usually intended to signal non-recoverable errors.运行时异常通常用于表示不可恢复的错误。 They don't force the caller to handle or declare them.它们不会强制调用者处理或声明它们。 And many of them indeed signal programming errors (like NullPointerException).它们中的许多确实表示编程错误(如 NullPointerException)。

  2. Because that's how the JLS define an unchecked exception: an exception that is or extends RuntimeException, which itself extends Exception.因为这就是 JLS 定义未检查异常的方式:属于或扩展 RuntimeException 的异常,它本身扩展了 Exception。 Using a single inheritance root allows handlong every possible exception in a single catch clause.使用单个继承根允许在单个 catch 子句中处理每个可能的异常。

Regarding your example: yes, the throws clause is mandatory, since IOException is a checked exception and that the code inside the method is susceptible to throw one.关于您的示例:是的,throws 子句是强制性的,因为 IOException 是一个已检查的异常,并且该方法内的代码容易抛出异常。

The compiler only makes sure a method can't throw a checked exception if it didn't declare it.编译器只确保一个方法在没有声明它的情况下不能抛出一个已检查的异常。 It is a general belief that such checking by compiler should be done for the exceptions whose occurrence is outside programmer's control, such as the examples you cite (database connectivity, files missing, etc.).人们普遍认为,编译器应该对发生在程序员控制之外的异常进行此类检查,例如您引用的示例(数据库连接、文件丢失等)。 Unchecked exceptions are "not supposed to happen", so the compiler doesn't force you to declare them.未经检查的异常“不应该发生”,因此编译器不会强迫您声明它们。

As for simulating IOException or any other, it is trivial:至于模拟IOException或任何其他,它是微不足道的:

throw new IOException();

In your example the prompt method may throw an IOException , that's why it needs to declare it.在您的示例中, prompt方法可能会抛出IOException ,这就是它需要声明它的原因。 This has nothing to do with how you handle the exception at the point you call the method.这与您在调用方法时如何处理异常无关。

RuntimeException is a subclass of Exception to make it convenient to catch all exceptions with one catch Exception clause. RuntimeExceptionException一个子类,它可以方便地使用一个catch Exception子句捕获所有异常。 This could have been designed differently;这本来可以设计成不同的; Java's exception class hierarchy is a mess. Java 的异常类层次结构一团糟。

If you dont put throws clause in here then this error will occur如果你不在这里放 throws 子句,就会出现这个错误

ThrowsDemo.java:5: unreported exception java.io.IOException; ThrowsDemo.java:5: 未报告的异常 java.io.IOException; must be caught or d eclared to be thrown return (char) System.in.read();必须被捕获或声明被抛出 return (char) System.in.read();

so throws clause in necessary.所以在必要时抛出子句。

Five example of checked exception and unchecked exception.已检查异常和未检查异常的五个示例。

Unchecked Exception
   -- NullPointerException
   -- ArrayIndexOutofBound
   -- IllegalArgument Exception
   -- ClassCastException
   -- IllegalStateException
   -- ConcurrentModificationException

Checked Exception Five Example
   -- FileNotFoundException
   -- ParseException
   -- ClassNotFoundException
   -- CloneNotSupportException
   -- SQLException

Checked and unchecked exceptions检查和未检查异常

There are two types of exceptions: checked exceptions and unchecked exceptions.有两种类型的异常:已检查异常和未检查异常。 The main difference between checked and unchecked exception is that the checked exceptions are checked at compile-time while unchecked exceptions are checked at runtime.已检查异常和未检查异常之间的主要区别在于,已检查异常在编译时检查,而未检查异常在运行时检查。

Please read this article to get a clear idea.请阅读这篇文章以获得一个清晰的想法。

More Details 更多细节

Use checked exceptions when the client code can take some useful recovery action based on information in exception.当客户端代码可以根据异常信息采取一些有用的恢复操作时,使用检查异常。 Use unchecked exception when client code cannot do anything.当客户端代码不能做任何事情时,使用未经检查的异常。 For example, convert your SQLException into another checked exception if the client code can recover from it and convert your SQLException into an unchecked (ie RuntimeException) exception, if the client code cannot do anything about it.例如,如果客户端代码可以从中恢复,则将您的 SQLException 转换为另一个已检查的异常;如果客户端代码对此无能为力,则将您的 SQLException 转换为未检查的(即 RuntimeException)异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM