6

When handling errors in Java it's common to see the superclasses being the errors that are caugh, such as

Exception, IOException, SocketException, etc.

However how do you go about finding the nitty-gritty details on the exception? How do you single a certain exception type out from the others. For instance, I'm currently working on a small project using Netty.io which throws an IOException for every type of read/write error you can name. This makes sense, because ultimately this is input/output errors, but how would I handle them individually.

Example exceptions:

java.io.IOException: An existing connection was forcibly closed by the remote host
java.io.IOException: Connection reset by peer
java.io.IOException: Stream closed

The list just continues to go on, but how would you go about handling these seperately, one approach that I've found while looking around and seems really nasty is the following.

try { 
    // ...
} catch (IOException e) { 
    if(e.getMessage().contains("An existing connection was forcibly closed by the remote host")) {
        // Handle error
    } else //...
}

This seems very tedious and there's bound to be a better way to do this, a correct way if you will. I've looked through quite a bit of error handling writeups over the last few hours and they all only talk about the big boys that are used commonly. IOException, Exception, SocketException, NullPointerException, and FileNotFoundException. Where I believe SocketException and FileNotFoundException would be directly related to the IOException, more than likely a subclass, correct me if I'm wrong.

Anyway, what's the proper way to go about handling these exceptions and how do you figure out exactly what kind of exception you need to be handling? All I can really do is handle IOException until something more precise comes up, but when developing applications it's always good to be able to handle each error uniquely.

M A
  • 71,713
  • 13
  • 134
  • 174
Hobbyist
  • 15,888
  • 9
  • 46
  • 98
  • When developing applications, you would encapsulate exceptions that deserve to be handled differently as exceptions of different types. Then you don't need to deal with their messages to know specialties. – Bruno Toffolo Apr 07 '15 at 20:16
  • Because the library you use only throws `IOException` with different messages, string comparison is the only way to distinguish. Are you sure you can and want to handle the different cases differently? In practice I found, one can rarely properly handle individual exceptions so this problem is avoided by just treating all similar exceptions the same. – Richard Apr 07 '15 at 20:24
  • @Richard The library may only have been *declared* to throw 'IOException` but that doesn't mean it can't throw derived exceptiosn. You would have to experiment. – user207421 Apr 08 '15 at 03:38

3 Answers3

2

In most of these cases the message is irrelevant from the point of view of your code. It's just something to be shown to the user, or logged. The only salient fact is that the connection is broken, for whatever reason, and there aren't different code paths you can use depending on which message it was.

The only one that's different is 'socket closed', which indicates a coding bug.

EDIT Regarding your comments below:

  • Any IOException other than SocketTimeoutException on a socket is fatal to the connection.
  • Invalid packets don't cause IOException: that's an application-layer problem that throws application-layer exceptions, or subclasses of IOException: e.g., java.io.StreamCorruptedException.
  • There is no such thing as IOException: connection closed by remote host. If the peer closes the connection, that causes an end-of-stream condition, which manifests itself as either read() returning -1, readLine() returning null, or readXXX() throwing EOFException for any other X.
user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    So, the message thrown by the exception is completely irrelevant to the logic that the code should handle? I would have to disagree when writing server applications. For example if the IOException was complaining about invalid packet lengths versus a disconnection of a user. Perhaps when the user is disconnected because of a certain event you'd want to cache their data in memory so they can sign back online quickly and efficiently without loading all of their user data from the database again. I may be wrong, still trying to grasp a better understanding of this. – Hobbyist Apr 07 '15 at 20:19
  • It just seems like if the user disconnects due to a networking glitch, rather than the user just logging off (Which would throw the "Connection closed by remote host" message) you may want to follow another process. – Hobbyist Apr 07 '15 at 20:19
  • 3
    @Christian.tucker It sounds like you are overcomplicating it. It is very rare (not impossible, just rare) that you should need to know what the message is in your code for any exception. That's the whole point of exception typing. For all the corner cases you listed, I would recommend a single course of actions (eg: saving user state on disconnect in ANY case). – MadConan Apr 07 '15 at 20:31
1

I would suggest catching the exceptions in order, from most specific to least - such that you will notice a circuit break pattern when the exception you are looking for is reached. This is the best I can come up with:

try {
   /// Something that can result in IOException or a SocketException
catch (IOException e){
   //Do something specific
}catch (SocketExcpetion e){

}catch (Exception e) { //or some superclass of the above exceptions
 ///
}

Don't forget that you can also catch multiple exceptions of different types using the | command: catch (IOException|SocketException|

edenzik
  • 146
  • 1
  • 4
  • Thanks for the tip, but the over-all point of the question was to find the specific type of exception, for example `IOException extends Exception` and `FileNotFoundException extends IOException` – Hobbyist Apr 07 '15 at 20:22
  • 2
    @Christian.tucker I am not sure if I understand your comment. In your question you seem to claim (unless I miserad it) that you are facing situation where you get precisely `IOExcepption` not some particular subclass of it like `FileNotFoundException` and that you need to handle them based on content of message. But in your comments you claim that "point of the question was to find the specific type of exception, for example IOException extends Exception and FileNotFoundException extends IOException". So do you get precise type (FileNotFoundException) or not (IOException)? – Pshemo Apr 07 '15 at 20:34
  • 1
    @Christian.tucker or are we talking about situation where method is declared to only throw IOException so compiler makes you to handle it, but in reality method can throw FileNotFoundException? In that case simply placing case for `FileNotFoundException` before case handling `IOException` should solve your problem. – Pshemo Apr 07 '15 at 20:40
1

The documentation (http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html) contains a long list of direct subclasses. You might want to look through them and check which ones you want to treat differently. Once you know that, you can use multiple catch-blocks, first the subclasses, then the most general IOException:

catch(SSLException se) {
  // do something
}
catch(HttpRetryException he) {
  // do something else
}
catch(IOException ioe) {
  // nop
}
afi
  • 488
  • 1
  • 5
  • 7