5

AFAIK, the standard try-with-resources form

try(InputStream is= new ...){
    ... some reading from is
} catch (..){
    ... catching real problems
}
catch (IOException e) {
    ... if closing failed, do nothing - this clause is demanded by syntax
}

is equivalent to:

try{
    InputStream is= new ...
    ... some reading from is
} catch (..){
    ... catching real problems
} finally {
    try{
        is.close();
    } catch (IOException e) {
        ... if closing failed, do nothing
    }
}

The first variant is more simple, of course. But I see the case when the second variant is absolutely OK, whereas the first becomes ununderstandable.

Imagine the situation, when you have got code, where the try(){} appears in the function with throws IOExceptions clause.

String readFromFile(...) throws IOException{
    ...
    try(...){
        ...
    }
}

The IOException in the second catch eats all IOExceptions, either connected to the attempt of closing or not. And does nothing. I suppose, that somewhere out of the method there is a piece of code that works with that IOException and does something noticeable. For example, logs the stack. So, local catches will be never reached. We are not interested in the second catch clause, but usually, we need some special reaction for the first one.

On the other hand, if we delete the closing catch(IOException e){} clause, counting on the throws in the method header, that absolutely uninteresting for us closing exception will be reacted to.

While we are catching the closing problems by IOException, I see no way out of the problem. And Eclipse java editor demands me to use this very exception for that clause!

How can I divide IOException appearing from closing from other IOExceptions, appearing in the try{} body?

Gangnus
  • 24,044
  • 16
  • 90
  • 149
  • maybe you can get the message and differentiate the exceptions in that way – XtremeBaumer Feb 09 '18 at 12:22
  • If I knew all possible problems, I could do it. But I don't. And agree, that the correct solution will be catching closing problems with some concrete exception, not naming all possible exceptions for the main try{} body. – Gangnus Feb 09 '18 at 12:30
  • @XtremeBaumer that would be very messy up the chain. How does a caller know that they need to make such a check? – Adam Feb 09 '18 at 12:30
  • @Adam he wants to ignore the `IOException` which can happen on closing. therefore he ahs to somehow determine which that is and throw everything else. the caller has nothing to do with it – XtremeBaumer Feb 09 '18 at 12:34
  • It's still useful if you don't need/want to differentiate Exceptions from close from the others (for instance, if you get an exception doing a close, it's possible a file wasn't flushed, you may want to proceed as if file wasn't fully written to, same path as a generic IOException). See also https://stackoverflow.com/q/6889697/32453 – rogerdpack Apr 16 '21 at 19:41
  • 1
    @rogerdpack Of course, you are right. Often we don't need it. but: 1. I am speaking about the cases when we NEED it. 2. I did not think about the case, I didn't fully understand the problem, but now I see that the thought of the solution of Adam is very useful, because even if we needn't differentiate now, the need can appear after some changes in either mother or daughter functions. And forgetting to serve this beforehand, we are breaking the OOP concept. – Gangnus Apr 17 '21 at 00:01

1 Answers1

4

I think Java is to blame for this one. The close() method should have thrown a different exception than IOException there is rarely anything the caller can do about it. Your only solution is to rewrap the IOExceptions you're interested in before rethrowing.

Usually what I do is I extract the entire content of the try-block to its own method where I can catch any IOExceptions and re-throw them as custom exceptions. I can then catch the remaining IOException by itself in the catch block.

public void foo() throws CustomException {

    try (InputStream is= new ...) {
        bar(is); //This catches internal IOExceptions and throws a CustomException
    }
    catch (IOException e) { //The close() exception
        

    }
}
rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Adam
  • 364
  • 2
  • 11
  • A good idea. Last times I started to like the massive use of rethrowing.. and you are giving here one more argument for it. Thank you. I already thought about uselessness of try-with-resources. – Gangnus Feb 09 '18 at 12:59
  • But after another thought, try-with-resources really looks useless. For its correct usage we need to make two-storey construction, same complexity as for usual try. Or even a bit higher. – Gangnus Feb 09 '18 at 15:08