简体   繁体   中英

Checked vs Unchecked Exceptions in Java

I am having some problems with understanding the differences between checked and unchecked exceptions in Java.

  1. Firstly, checked exceptions are supposed to look for abnormalities during compile time. 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.

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 ? What does this signify?

I found an example in Herbert Schildt's book explaining the usage of checked exceptions:

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? 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!):

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.

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; 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 :-) ; 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.

I personally think that also SQLException should be unchecked, since it denotes a bug in the program, or a connection problem to the database. But there are many examples where you get exception that you really don't have any clue in how to manage (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).

  1. you do not need to declare unchecked exceptions in a throws clause; but you must declare checked exceptions;
  2. RuntimeException and Error , and all of their subclasses ( IllegalArgumentException , StackOverflowError etc), are unckecked exceptions; the fact that RuntimeException is unchecked, unlike other Throwable subclasses, is by design;
  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. One famous such exception is NullPointerException , often abbreviated as NPE, which is a subclass of RuntimeException , and therefore unchecked.

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 .

Final note: if you have exception classes E1 and E2 and E2 extends E1 , then catching and/or throwing E1 also catches/throws 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.

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).

  2. Because that's how the JLS define an unchecked exception: an exception that is or extends RuntimeException, which itself extends Exception. Using a single inheritance root allows handlong every possible exception in a single catch clause.

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.

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:

throw new IOException();

In your example the prompt method may throw an IOException , that's why it needs to declare it. 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. This could have been designed differently; Java's exception class hierarchy is a mess.

If you dont put throws clause in here then this error will occur

ThrowsDemo.java:5: unreported exception java.io.IOException; must be caught or d eclared to be thrown 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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