javaexceptionexception-safeexception-safety

How do you know all the exceptions a method can throw


Is there a way to get some details regarding exception safety aspects of Java's standard classes? Mainly working with C++ and C#, I'm confused with Java exception specifications, so I need to understand the proper way of working with exceptions.

To be more specific, let's consider ServerSocket. It starts listening for incoming connections as soon as its object is constructed. Then, you should use accept() to accept the connection (if someone tries to connect).

In case you've previously configured your server socket with setSoTimeout(), there's a change that accept() will throw SocketTimeoutException because nobody tried to connect in a specified period of time. That's fine, server socket is still usable, so you just call accept() once again.

But SocketTimeoutException is not the only thing that accept() may throw. What does all the other exceptions mean? If I wrap call to accept() with 2 catch clauses: for SocketTimeoutException and IOException, can I still safely use the related ServerSocket instance after I got into IOException clause?

I'd really appreciate both Java-wide and ServerSocket-specific answers.


Solution

  • It is not safe to reuse the object. For such a question I would always look into a source, that is the reason it is open.

    So if you look into that one: http://kickjava.com/src/java/net/ServerSocket.java.htm you notice that in accept() a SocketException (inherits from IOException) is thrown if the socket is closed or not bound anymore. Both states indicate that the ServerSocket is not valid anymore.

    So for this class, generally, if you fail with an exception, always try to gracefully close the ServerSocket in a finally block and then recreate it.

    Additionally on your Java-wide question scope: Always look into the source and understand what the interface is doing. If it is mission-critical write tests that reproduce the behaviour (should not be easy at all with such a low-level api).

    Finally - is Java consistently doing such things that way? No. Some classes are stateless, others are not (like ServerSocket), some are thread-safe, others not. And you need to understand - either from the documentation or (mostly) from the code - what state they build in order to understand what to do when an Exception knocks you off from the main path.

    Most people curse those checked Java exceptions, because most of them (as with most of the IOExceptions) are not really recoverable in a meaningful way. Most of the time, they argue, you cannot understand each and every fine corner case. Which is the reason why many complex frameworks may retry twice or thrice if they think in this case they might, but finally throw a RuntimeException to a top framework layer. There they make something useful out of it (a meaningful error providing context) and log all the details they have, which is a huge stack trace most of the time. A great resource of knowledge, feared by many developers.

    So what can you do if you could not recover from an untested corner-case problem? Throw up (probably with a some subclass of RuntimeException) the most meaningful stacktrace annotated with all the context you have. Setup monitoring. And if you run into a frequent problem, fix it.