12

While learning Java I stumble upon this error quite often. It goes like this:

Unreported exception java.io.FileNotFound exception; must be caught or declared to be thrown.

java.io.FileNotFound is just an example, I've seen many different ones. In this particular case, code causing the error is:

OutputStream out = new BufferedOutputStream(new FileOutputStream(new File("myfile.pdf")));

Error always disappears and code compiles & runs successfully once I put the statement inside try/catch block. Sometimes it's good enough for me, but sometimes not.

First, examples I'm learning from do not always use try/catch and should work nevertheless, apparently.

Whats more important, sometimes when I put whole code inside try/catch it cannot work at all. E.g. in this particular case I need to out.close(); in finally{ } block; but if the statement above itself is inside the try{ }, finally{} doesnt "see" out and thus cannot close it.

My first idea was to import java.io.FileNotFound; or another relevant exception, but it didnt help.

Sejanus
  • 3,253
  • 8
  • 39
  • 52
  • Some info on the Sun website : [Exceptions](http://java.sun.com/docs/books/jls/second_edition/html/exceptions.doc.html) – garyj Jan 19 '10 at 06:40

2 Answers2

15

What you're referring to are checked exceptions, meaning they must be declared or handled. The standard construct for dealing with files in Java looks something like this:

InputStream in = null;
try {
  in = new InputStream(...);
  // do stuff
} catch (IOException e) {
  // do whatever
} finally {
  if (in != null) {
    try {
      in.close();
    } catch (Exception e) {
    }
  }
}

Is it ugly? Sure. Is it verbose? Sure. Java 7 will make it a little better with ARM blocks but until then you're stuck with the above.

You can also let the caller handle exceptions:

public void doStuff() throws IOException {
  InputStream in = new InputStream(...);
  // do stuff
  in.close();
}

although even then the close() should probably be wrapped in a finally block.

But the above function declaration says that this method can throw an IOException. Since that's a checked exception the caller of this function will need to catch it (or declare it so its caller can deal with it and so on).

cletus
  • 616,129
  • 168
  • 910
  • 942
  • "Handled" I suppose means try/catch. And what is "declared" in this case? – Sejanus Jan 19 '10 at 06:41
  • Declared means added to the method signature in a "throws" clause. – Stephen C Jan 19 '10 at 07:03
  • In the case where doStuff can throw an IOException, isn't it possible that if an exception is thrown before in.close() is run, doStuff will return and the "in" resource will never be closed? Outside of doStuff, there is no handle to close the resource. If this is true, this is a major anti-pattern in Java Exceptions... – twolfe18 Jan 04 '13 at 01:26
  • What on earth is an ARM block? – MC Emperor Apr 20 '21 at 13:07
4

Java's checked exceptions make programmers address issues like this. (That's a good thing in my opinion, even if sweeping bugs under the carpet is easier.)

You should take some appropriate action if a failure occurs. Typically the handling should be at a different layer from where the exception was thrown.

Resource should be handled correctly, which takes the form:

acquire();
try {
    use();
} finally {
    release();
}

Never put the acquire() within the try block. Never put anything between the acquire() and try (other than a simple assign). Do not attempt to release multiple resources in a single finally block.

So, we have two different issues. Unfortunately the Java syntax mixes up the two. The correct way to write such code is:

try {
    final FileOutputStream rawOut = new FileOutputStream(file);
    try {
        OutputStream out = new BufferedOutputStream(rawOut);
        ...
        out.flush();
    } finally {
        rawOut.close();
    }
} catch (FileNotFoundException exc) {
    ...do something not being able to create file...
} catch (IOException exc) {
    ...handle create file but borked - oops...
}
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Why not put acquire in the try block? – Rag Feb 14 '13 at 21:18
  • @BrianGordon If you put the acquire inside the `try`, you will run the release part (`finally`) even if the acquire fails, which is wrong. / Now you could attempt some code to check if the acquire succeeded and only then run the release. However experience suggests that is usually written incorrectly (and clearly not tested), so you might as well go for the simpler code. – Tom Hawtin - tackline Feb 16 '13 at 16:52