基于来自异常的消息来控制程序流是个好主意吗?
Is it good idea to control program flow based on message from Exception?
例如我有一个 TCP 服务器:
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;
}
}
如果 ServerSocket::accept
抛出 SocketException: Too many open files
,我只想记录异常,但保留 运行 我的 TCP 服务器线程并在几秒睡眠后重试接受。但在任何其他情况下,服务器线程都必须完成。
我可以在这里安全地使用来自异常的消息并确保异常消息在每个实现中始终相同吗?或者是否存在更好的检测方法?
解决方案
谢谢你们的精彩回答。在我的示例中只能捕获 SocketException
而不是任何子类。 ServerSocket 和 SocketException 都没有任何 getStatusCode()
方法。所以我最终为我的示例选择了以下简化的解决方案:
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;
}
}
不,这绝对是一个anti模式。 Exception messages 应该被视为人类可读的信息,nothing 其他。它们 而不是 意味着以编程方式进行评估。时期。 (是的,有些系统实际上以编程方式查看消息 - 但这更多的是 "meta" 分析,寻找 "patterns",而不是进行严格的 "string equals" 检查)
事实是:这些异常不受您的控制。意思是:你不会注意到它们的实现何时发生变化。这些消息 的确切 content/layout 在未来某个时间点发生变化 的可能性不大,但仍有可能。然后你的整个代码就崩溃了。
换句话说:如果您需要 distinct 错误处理,那么您的代码应该抛出 distinct 不同类型的异常。
郑重声明:我并不是说 简单 解决方案指日可待。但是你选择的那个,正如所说,更像是一种反模式。
我 100% 同意 GhostCat,错误消息取决于底层实现,应该只用于日志记录。
也许你可以找到一个解决方案来决定在异常情况下做什么,如果你处理异常原因:
也许您可以找到之前在堆栈跟踪中发生的 "too many files" 异常。
例如我有一个 TCP 服务器:
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;
}
}
如果 ServerSocket::accept
抛出 SocketException: Too many open files
,我只想记录异常,但保留 运行 我的 TCP 服务器线程并在几秒睡眠后重试接受。但在任何其他情况下,服务器线程都必须完成。
我可以在这里安全地使用来自异常的消息并确保异常消息在每个实现中始终相同吗?或者是否存在更好的检测方法?
解决方案
谢谢你们的精彩回答。在我的示例中只能捕获 SocketException
而不是任何子类。 ServerSocket 和 SocketException 都没有任何 getStatusCode()
方法。所以我最终为我的示例选择了以下简化的解决方案:
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;
}
}
不,这绝对是一个anti模式。 Exception messages 应该被视为人类可读的信息,nothing 其他。它们 而不是 意味着以编程方式进行评估。时期。 (是的,有些系统实际上以编程方式查看消息 - 但这更多的是 "meta" 分析,寻找 "patterns",而不是进行严格的 "string equals" 检查)
事实是:这些异常不受您的控制。意思是:你不会注意到它们的实现何时发生变化。这些消息 的确切 content/layout 在未来某个时间点发生变化 的可能性不大,但仍有可能。然后你的整个代码就崩溃了。
换句话说:如果您需要 distinct 错误处理,那么您的代码应该抛出 distinct 不同类型的异常。
郑重声明:我并不是说 简单 解决方案指日可待。但是你选择的那个,正如所说,更像是一种反模式。
我 100% 同意 GhostCat,错误消息取决于底层实现,应该只用于日志记录。
也许你可以找到一个解决方案来决定在异常情况下做什么,如果你处理异常原因:
也许您可以找到之前在堆栈跟踪中发生的 "too many files" 异常。