2

I've created a class like below and am wondering why I am unable to simply catch and rethrow an exception:

public class TestClass implements Runnable {
    @Override
    public void run() {
        try{
            FileInputStream inStream = new FileInputStream("");
        }catch(Exception e){
            throw e;
        }
    }
}

Eclipse is showing a compilation error: "Unhandled exception type FileNotFoundException" and suggests the following fix, which for some reason compiles fine:

@Override
public void run() {
    try{
        FileInputStream istream = new FileInputStream("");
    }catch(Exception e){
        try {
            throw e;
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }
}

What is going on here?

Azianese
  • 554
  • 7
  • 21
  • 3
    because run() method in the interface is not declared to throw exceptions. – OldProgrammer Jul 20 '20 at 23:27
  • 3
    Exception is a checked exception, so any method that throws it has to declare it in the `throws` clause. You can't throw it from `Runnable.run()` because the interface doesn't declare that that exception may be thrown. – khelwood Jul 20 '20 at 23:27
  • @khelwood Thanks, that makes sense. I was wondering why throwing a different exception like NullPointerException compiles fine. But now I'm wondering why the additional try-catch within the original catch seems to work? – Azianese Jul 20 '20 at 23:34
  • @khelwood To clarify my comment above since I can't edit it anymore: That answers why* throwing a different exception compiles fine. And if you would like to create an answer, I'll accept it – Azianese Jul 20 '20 at 23:41
  • Because `NullPointerException` is an unchecked exception. (Read the Oracle Java tutorial on exceptions which explains the difference between checked and unchecked exceptions.) I'm not convinced that the effort of writing an answer is warranted. These questions have surely been asked and answered many times before. What is really needed is for someone to find appropriate "dup" links. – Stephen C Jul 20 '20 at 23:44
  • 1
    It is worth noting that that solution suggested by Eclipse is normally a bad idea. Certainly ... in production code. – Stephen C Jul 20 '20 at 23:50
  • Alternatively, you could `throw new UncheckedIOException(e);` – Bohemian Jul 20 '20 at 23:50
  • @StephenC indeed: [Why is exception.printStackTrace() considered bad practice?](https://stackoverflow.com/questions/7469316) – Bohemian Jul 20 '20 at 23:54
  • (Assuming I'm looking in the right place) my Eclipse version is listed as 4.4.2.20150219-0708. Of note is that I'm using a slightly modified in-house version of Eclipse. – Azianese Jul 21 '20 at 00:10

1 Answers1

2

The constructor of FileInputStream declares to throw a checked exception. According to the so-called catch or specify requirement, this means that methods that throw exceptions of this type must either catch it (which excludes rethrowing it), or declare it in their interface. Because your run method does not declare it (and you can't because it overrides Runnable#run()), you get the error.

If you catch the exception and swallow it with a print statement, then you meet the "catch" requirement and the error disappears. If you throw an exception that extends RuntimeException instead, this is an unchecked exception and the catch or specify requirement does not apply.

Interestingly, the flow analysis done by the Eclipse compiler is slightly over-aggressive, which leads to the confusing and potentially incomplete error message

Unhandled exception type FileNotFoundException

An example where this type specificity would be incomplete is if you have the following code in your try block:

Class.forName("foo");
FileInputStream inStream = new FileInputStream("");

Then you'll still get an error about FileInputStream, even though forName would also result in an unhandled checked exception of a different type (ClassNotFoundException).

SDJ
  • 4,083
  • 1
  • 17
  • 35