5

Let's say I have the following Java interface that I may not modify:

public interface MyInterface {
  public void doSomething();
}

And now the class implementing it is like this:

class MyImplementation implements MyInterface {
  public void doSomething() {
    try {
      // read file
    } catch (IOException e) {
      // what to do?
    }
  }
}

I can't recover from not reading the file.

A subclass of RuntimeException can clearly help me, but I'm not sure if it's the right thing to do: the problem is that that exception would then not be documented in the class and a user of the class would possibly get that exception an know nothing about solving this.

What can I do?


We all agree: the interface is faulty.

Solution I chose

I finally decided to write a MyVeryOwnInterface that extends MyInterface and adds as part of the signature of the faulty methods the MyRuntimeException:

public interface MyVeryOwnInterface extends MyInterface {
  public void doSomething() throws MyRuntimeException;
}
class MyImplementation implements MyVeryOwnInterface {
  public void doSomething() throws MyRuntimeException {
    try {
      // read file
    } catch (IOException e) {
      throw new MyRuntimeException("Could not read the file", e);
    }
  }
}
Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137

6 Answers6

8

You've encountered the problem of leaky abstractions. There is no really good solution, and using a RuntimeException pretty much the only thing you can do.

Arguably, this is also an example for why checked exceptions are a failed concept.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • Or it's an example of why "doSomething" has too many responsibilities. – CPerkins Apr 29 '10 at 16:59
  • 3
    Ok, thanks for the principle of leaky abstractions. However, it's the first time in 10 years of experience in Java that I encounter this issue, that's not what I would call a "failed concept". – Olivier Grégoire Apr 29 '10 at 17:20
  • 6
    Of course checked exceptions are not a 'failed concept'. They are extremely useful. In this case the failure is with the the interface designer, not the language designer. – DJClayworth Apr 29 '10 at 17:56
  • 3
    @DJClayworth: So I assume all methods in all interfaces you design throw IOException, SQLException and RemoteException, just in case someone implements them and uses File IO, a databse or RMI? No, this is a perfect example for checked exceptions being an utter failure. They lead to ugly, cluttered code and can't even deliver what they promise. – Michael Borgwardt Apr 29 '10 at 19:43
  • When I face a checked exception, what I usually do is chain it in my own checked exception, which is also fully documented. If needed I chain it in an unchecked exception, again of my own and document this. There is absolutely no need to throw further the IOException, SQLException or whatever other checked exception. Encapsulating them in a new one is perfect (checked or unchecked). The case I mentioned in the initial issue is special because there is no place for *any* exception: nor checked or unchecked. – Olivier Grégoire Apr 29 '10 at 20:17
  • @Michael Borgwardt Yes. All interfaces I design where there might be such a failure specify an allowable behaviour in that case; either a checked exception (which can wrap an IO exception if necessary) or something else. See my answer to this question. – DJClayworth Apr 29 '10 at 21:11
  • @MichaelBorgwardt so essentially you argue that all Java methods should be written to `throws Exception`? – Thorbjørn Ravn Andersen Oct 13 '12 at 13:17
  • @Thorbjørn Ravn Andersen: no, I'm arguing that checked exception should be avoided as much as possible. – Michael Borgwardt Oct 13 '12 at 20:25
  • @MichaelBorgwardt this is impossible with the current runtime libraries. – Thorbjørn Ravn Andersen Oct 14 '12 at 06:43
  • 1
    @Thorbjørn Ravn Andersen: thus "as much as possible", and what you suggest in your answer. – Michael Borgwardt Oct 14 '12 at 08:52
3

I'd throw a new IOError(e); and file an issue at the maintainer of the interface.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
2

If you can't recover than you need to throw and thus wrap it into a RuntimeException or an Error and throw that.

public class Unchecked extends Error {

   private final Exception source;

   public Unchecked( Exception source) {
       this.source = source;
   }

   public String toString() {
       return "Unchecked Exception, Caused by: " + source;
   }

   public Exception getSource() {
       return source;
   }

   public static Unchecked wrap( Exception cause ) {
       return new Unchecked(cause);
   }
}
openCage
  • 2,735
  • 1
  • 18
  • 24
1

Clearly the interface designer is at fault for not considering the possibility that doSomething() may fail. Ideally he should have either allowed IOException to be thrown (if he suspected that IO wouldbe invovled) or a SomethingException (checked) which you could use to wrap your IOException.

If the interface designer is available to you, talk to them and ask what they expected to happen in the case of failure. Maybe they can change the interface: or maybe it is acceptable to fail silently according to the interface's contract.

Failing all of these you are reduced to a choice of failing silently (possibly recording but not responding to the problem) or throwing a RuntimeException which may terminate the process.

DJClayworth
  • 26,349
  • 9
  • 53
  • 79
0

I don't think there is anything to do except to declare throws IOException in the interface. That is simply the nature of Java interfaces and checked exceptions.

You could have another method in your class (doSomethingDangerous) that throws the IOException. From the doSomething-implementation, you simply call doSomethingDangerous (wrapped in a try/catch) and then where ever you wish to be careful about doingSomething you call doSomethingDangerous directly.

aioobe
  • 413,195
  • 112
  • 811
  • 826
0

I would suggest

throw new RuntimeException("while reading file " + fileName + "...", e);

Isn't the problem here, that the interface does not expect any problems at all?

(and you may want to create your own OurCompanyDomainException extends RuntimeException to make it easy to distinguish in the code on the other side of the interface).

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347