你怎么知道一个方法可以抛出的所有异常
有没有办法获得有关 Java 标准类的异常安全方面的一些详细信息?主要使用 C++ 和 C#,我对 Java 异常规范感到困惑,所以我需要了解处理异常的正确方法。
更具体地说,让我们考虑一下 ServerSocket。一旦构造了它的对象,它就开始侦听传入的连接。然后,您应该使用 accept()
接受连接(如果有人尝试连接)。
如果您之前使用 setSoTimeout()
配置了服务器套接字,则 accept()
将抛出 SocketTimeoutException
,因为没有人尝试这样做在指定时间内连接。没关系,服务器套接字仍然可用,因此您只需再次调用 accept()
即可。
但SocketTimeoutException
并不是accept()
可能抛出的唯一异常。所有其他例外意味着什么?如果我用 2 个 catch 子句包装对 accept()
的调用:对于 SocketTimeoutException
和 IOException
,我仍然可以安全在进入 IOException 子句后使用相关的 ServerSocket 实例吗?
我真的很感激 Java 范围和 ServerSocket 特定的答案。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
重用该对象是不安全的。对于这样的问题,我总是会查找来源,这就是它开放的原因。
因此,如果您研究一下: http://kickjava.com/src/java /net/ServerSocket.java.htm 您注意到,在
accept()
中,如果套接字关闭或不再绑定,则会抛出 SocketException(继承自 IOException)。这两种状态都表明 ServerSocket 不再有效。因此,对于此类,通常,如果因异常而失败,请始终尝试在finally块中优雅地关闭ServerSocket,然后重新创建它。
另外,关于 Java 范围的问题范围:始终查看源代码并了解接口正在做什么。如果是重现行为的关键任务编写测试(使用如此低级的 api 应该不容易)。
最后——Java 一直都是这样做的吗?不是。有些类是无状态的,有些则不是(如 ServerSocket),有些是线程安全的,有些则不是。您需要了解 - 无论是从文档还是(主要)从代码 - 它们构建的状态,以便了解当异常将您从主路径中剔除时该怎么做。
大多数人咒骂那些已检查的 Java 异常,因为它们中的大多数(与大多数 IOException 一样)实际上无法以有意义的方式恢复。他们认为,大多数时候,你无法理解每一个细微的极端情况。这就是为什么许多复杂的框架可能会重试两次或三次(如果他们认为在这种情况下可能会重试),但最终会向顶层框架层抛出 RuntimeException 。在那里,他们从中得到一些有用的东西(提供上下文的有意义的错误)并记录他们拥有的所有详细信息,这在大多数情况下是一个巨大的堆栈跟踪。许多开发人员都害怕的巨大知识资源。
那么,如果您无法从未经测试的极端情况问题中恢复,该怎么办?抛出(可能是 RuntimeException 的某个子类)最有意义的堆栈跟踪,并用您拥有的所有上下文进行注释。设置监控。如果您经常遇到问题,请解决它。
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.
是的。该对象仍然存在 - 可能处于错误状态,在这种情况下它将引发其他异常,直到该问题得到纠正。
Yes. The object still exists - May be in an error state in which case it will throw other exceptions until that is rectified.
如果您阅读 ServerSocket 的规范,你会看到它抛出一个 IOException“如果等待连接时发生 I/O 错误”。再次在套接字上
accept()
是否安全?是的。您会再次抛出相同的异常吗?很可能是这样。If you read the specification for ServerSocket, you will see that it throws an IOException "if an I/O error occurs when waiting for a connection." Is it safe to
accept()
on the socket again? Yes. Are you going to get the same Exception thrown again? Likely so.我还没有找到一种简单的方法来查看对象是否仍处于可用状态。每个对象都有自己的规则。
在您使用 ServerSocket 的特定情况下,我会尝试以下两种不同的操作之一:
运行 netstat 或其他实用程序以查看操作系统认为套接字正在做什么。如果操作系统认为它没有在监听,那么就发生了一些事情。
或
编写一个测试程序来抛出异常并看看它会做什么。我一直这样做(特别是使用专有软件)。在您选择的 ServerSocket 情况下,这会更困难,因为我能想到的所有场景(例如,地址正在使用、权限不足等)都不会导致对象仍然有效。
I have not yet found an easy way to see if an object is still in a usable state. Each object makes its own rules.
In your specific case with ServerSocket I would try one of two different things:
Run netstat or some other utility to see what the OS thinks that the socket is doing. If the OS doesn't think it is listening, then something happened.
or
Write a test program that will throw the exception and see what it does. I do this all the time (especially with proprietary software). It would be harder in the ServerSocket case you picked, since all of the scenarios I can think of (e.g. address in use, insufficient privileges, etc.) would never result in an object being still valid.
根据 javadoc,声明的异常是
IOException
、SecurityException
、SocketTimeoutException
和IllegalBlockingModeException
。SecurityException
和IllegalBlockingModeException
仅发生在特定上下文中,您不应尝试捕获和处理它们。 (它们不是您想要尝试恢复的问题!)当“某些其他 I/O 错误”发生时,IOException
情况就会发生。 javadoc 没有指定这些 I/O 错误可能是什么,但可能性可能包括以下内容:(事实上,javadoc没有说明可能抛出哪些
IOException
子类,这暗示您不应该尝试做聪明的事情来尝试恢复,如果这样做,您的代码很可能是。依赖于平台。)是和不是。从某种意义上说,它是安全的,因为您不会将应用程序置于比现在更糟糕的状态。另一方面,不能保证下一个
accept
调用不会失败同样的问题。如果您的应用程序打算作为无人值守的服务器运行,我认为您没有太多选择,只能记录 IOException 并重试...希望问题是暂时的。
According to the javadoc, the declared exceptions are
IOException
,SecurityException
,SocketTimeoutException
andIllegalBlockingModeException
. TheSecurityException
andIllegalBlockingModeException
only occur in specific contexts and you should not attempt to catch and handle them. (They are not problems you want to try to recover from!) TheIOException
case occurs when "some other I/O error" occurs. The javadoc does not specify what those I/O errors might be, but possibilities might include such things as:(The fact that the javadoc doesn't say which
IOException
subclasses might be thrown is a hint that you shouldn't try to do clever things to try to recover. If you do, your code is likely to be platform dependent.)Yes and no. It is safe in the sense that you won't put your application into a worse state than it is already in. On the other hand, there is no guarantee that the next
accept
call won't fail with the same problem.If your application is intended to run as an unattended server, I don't think you have much choice but to log the
IOException
and try again ... hoping that the problem is transient.您可以在
setsoTimeout
的 javadoc 中找到答案,它说:You can find your answer to the javadoc of
setsoTimeout
, it says :