For example I have a TCP server:
ServerSocket serverSocket = new ServerSocket(12345)
boolean doAccept = true;
while (doAccept) {
try {
serverSocket.accept();
} catch (SocketException e) {
if (serverSocket.isClosed()) {
LOGGER.info("Server stopped.", e);
doAccept = false;
} else if (e.getMessage().equals("Too many open files")) {
LOGGER.warn("Unable to accept. Will retry in 5 seconds.", e);
Thread.sleep(5_000);
} else {
LOGGER.error("Socket error.", e);
doAccept = false;
}
} catch (IOException e) {
LOGGER.error("I/O error.", e);
doAccept = false;
}
}
If ServerSocket::accept
throws a SocketException: Too many open files
, I would like only to log the exception but keep running my TCP server thread and retry accept after a few sec sleep. But in any other cases server thread must be done.
Can I use here safely the message from exception and make sure exception message is always same on every implementation? Or exists any better way to detect that?
SOLUTION
Thank you guys for great answers. Only SocketException
and not any subclasses can be catched in my example. Neither ServerSocket nor SocketException have any getStatusCode()
method. So I choosed the following simplified solution for my example finally:
ServerSocket serverSocket = new ServerSocket(12345)
boolean doAccept = true;
while (doAccept) {
try {
serverSocket.accept();
} catch (SocketException e) {
if (serverSocket.isClosed()) {
LOGGER.info("Server stopped.", e);
doAccept = false;
} else {
LOGGER.warn("Unable to accept. Will retry in 5 seconds.", LOGGER.error("Socket error.", e);
Thread.sleep(5_000);
}
} catch (IOException e) {
LOGGER.error("I/O error.", e);
doAccept = false;
}
}
No, this is definitely an anti pattern. Exception messages should be seen as human readable information, and nothing else. They are not meant to be programmatically evaluated. Period. ( and yes, there are systems that actually do programmatically look into messages - but that is more of a "meta" analysis, looking for "patterns", not doing hard "string equals" checking )
Thing is: these exceptions aren't under your control. Meaning: you won't notice when their implementation changes. It is not very likely, but still possible that the exact content/layout of these messages changes at some point in the future. And then your whole code falls apart.
In other words: if you need distinct error handling, then your code should be throwing distinct different kinds of exceptions.
And for the record: I am not saying that there are easy solutions just around the corner. But the one you choose, is as said, more of an anti pattern.