有没有办法获得有关Java标准类的异常安全方面的一些细节?主要使用C ++和C#,我对Java异常规范感到困惑,因此我需要了解处理异常的正确方法。
更具体地说,让我们考虑一下ServerSocket
。一旦构造了对象,它就开始侦听传入的连接。然后,您应该使用accept()
接受连接(如果有人试图连接)。
如果您之前已使用setSoTimeout()
配置了服务器套接字,则accept()
将引发SocketTimeoutException
的更改,因为没有人尝试在指定的时间段内进行连接。没关系,服务器套接字仍然可用,所以你只需再次调用accept()
。
但是SocketTimeoutException
并不是accept()
可能抛出的唯一东西。所有其他例外意味着什么?如果我使用2个catch子句调用accept()
:对于SocketTimeoutException
和IOException
,我仍可以安全地使用相关的ServerSocket
实例。进入IOException
条款?
我非常感谢Java范围和特定于ServerSocket的答案。
答案 0 :(得分:3)
重用该对象是不安全的。对于这样一个问题,我总是会考虑一个来源,这就是它开放的原因。
因此,如果你研究那个:http://kickjava.com/src/java/net/ServerSocket.java.htm你注意到在accept()
中,如果套接字关闭或不再绑定,则抛出SocketException(继承自IOException)。两种状态都表明ServerSocket不再有效。
因此,对于此类,通常情况下,如果因异常而失败,请始终尝试在finally块中正常关闭ServerSocket,然后重新创建它。
此外,在您的Java范围问题范围内:始终查看源代码并了解界面正在执行的操作。如果它是关键任务的写测试,可以重现行为(对于这样的低级api来说应该不容易)。
最后 - Java一直在做这样的事情吗?不是。有些类是无状态的,有些类不是(比如ServerSocket),有些是线程安全的,有些则不是。而且你需要理解 - 无论是从文档还是(大部分)来自代码 - 他们构建了什么状态,以便了解当Exception从主路径中解雇时你该做什么。
大多数人都会诅咒那些已检查的Java异常,因为大多数(与大多数IOExceptions一样)都无法以有意义的方式恢复。大多数时候,他们争辩说,你无法理解每一个细角的案例。这就是为什么许多复杂的框架可能会重试两次或三次的原因,如果他们认为可能会这样,但最终会将RuntimeException抛出到顶层框架层。在那里,他们从中创造了一些有用的东西(一个有意义的错误提供上下文)并记录他们拥有的所有细节,这在大多数情况下是一个巨大的堆栈跟踪。许多开发人员担心的知识资源很多。
那么如果你无法从未经测试的角落问题中恢复,你会怎么做?抛出(可能有一些RuntimeException的子类)最有意义的堆栈跟踪,用你拥有的所有上下文注释。设置监控。如果遇到常见问题,请修复它。
答案 1 :(得分:1)
是。该对象仍然存在 - 可能处于错误状态,在这种情况下,它会抛出其他异常,直到纠正完毕。
答案 2 :(得分:1)
如果您阅读了ServerSocket的规范,那么在等待连接时发生I / O错误时,您将看到它抛出IOException。再次对套接字accept()
安全吗?是。你是否会再次抛出同样的异常?可能是这样。
答案 3 :(得分:1)
我还没有找到一种简单的方法来查看对象是否仍处于可用状态。每个对象都有自己的规则。
在您使用ServerSocket的特定情况下,我会尝试两种不同的方法之一:
运行netstat或其他一些实用程序,以查看操作系统认为套接字正在执行的操作。如果操作系统不认为它在听,那就发生了一些事情。 或
编写一个测试程序,它将抛出异常并查看它的作用。我一直这样做(特别是使用专有软件)。在您选择的ServerSocket案例中会更难,因为我能想到的所有场景(例如使用中的地址,权限不足等)都不会导致对象仍然有效。
答案 4 :(得分:1)
但是SocketTimeoutException并不是accept()可能抛出的唯一东西。所有其他例外意味着什么?
根据javadoc,声明的例外情况为IOException
,SecurityException
,SocketTimeoutException
和IllegalBlockingModeException
。 SecurityException
和IllegalBlockingModeException
仅出现在特定上下文中,您不应尝试捕获和处理它们。 (它们不是您想要尝试恢复的问题!)IOException
情况发生在“发生其他一些I / O错误”时。 javadoc没有指定那些I / O错误可能是什么,但可能包括以下内容:
(javadoc没有说明可能抛出哪个IOException
子类这一事实暗示你不应该尝试做一些聪明的事情来尝试恢复。如果你这样做,你的代码可能会取决于平台。)
如果我使用2个catch子句调用accept():对于SocketTimeoutException和IOException,在进入IOException子句后,我还能安全地使用相关的ServerSocket实例吗?
是和否。从某种意义上来说,它是安全的,你不会让你的应用程序处于比现在更糟的状态。另一方面,无法保证下一个accept
调用不会因同样的问题而失败
如果您的应用程序要作为无人值守服务器运行,我认为您没有多少选择,只能记录IOException
并再试一次...希望问题是暂时的。
答案 5 :(得分:0)
您可以找到setsoTimeout
的javadoc的答案,它说:
使用指定的超时启用/禁用SO_TIMEOUT,以毫秒为单位。如果将此选项设置为非零超时,则对此ServerSocket的accept()调用将仅阻止此时间。如果超时到期,则引发java.net.SocketTimeoutException,尽管ServerSocket仍然有效。必须在进入阻止操作之前启用该选项才能生效。超时必须> 0.超时为零被解释为无限超时。