繁体   English   中英

为什么NullPointerException是运行时异常而RemoteException不是?

[英]Why NullPointerException is a runtime exception and RemoteException not?

可能的原因是因为NullPointerException是一个运行时异常是因为每个方法都可以抛出它,因此每个方法都需要“抛出NullPointerException”,并且会很难看。 但这会发生在RemoteException上。

并且可能的原因是因为RemoteException不是运行时异常,就是告诉客户端处理异常。 但是远程环境中的每个方法都需要抛出它,因此抛出NullPointerException没有区别。

猜测? 我清楚了吗?

我不会讨论这个决定,我只是引用Ann Wollrath(他领导Java RMI的设计和实现)的决定的解释。 这是从RMI-USERS档案中的这条消息中提取的(1999年1月的消息):

将RemoteException作为一个已检查的异常并要求远程方法在其throws子句中列出异常的决定并不是宗教性的。 该决定基于如何使分布式计算可靠。 这个问题偶尔出现在我们的用户列表中。 我刚才发布了一个详细的回复。 如果您有兴趣,请点击这里。 我在rmi-users存档中找不到它,所以我将其包含在下面。

干杯,

- 安


我想解决使RemoteException成为检查异常而不是RuntimeException的基本原理。

1)网络不可靠

我希望他们是,但事实上,他们不是。 每个网络都有短暂的故障。 您可以构建网络冗余,但事实是大多数网络都没有。 内联网有短暂的故障,互联网也是如此。 因此,每个RPC都会出现故障。 失败的类型本身可能与“网络”无关; 如果您的服务器用完文件描述符,您的客户端将获得连接异常。 从网络被破坏的意义上讲,这不是网络故障; 您的服务器处于资源匮乏的暂时状态。

RMI的目的不仅仅是处理单个机器崩溃时整个网络崩溃的有限情况。 这样的网络将被认为是可靠的,无论是一切都结束还是一切都失败了 - 没有部分失败。 RMI针对更广泛的受众。

2)无法从客户端隐藏RPC故障

部分失败是分布式编程的事实; 这些失败不能隐藏到程序中。 客户端出现故障,无论是检查异常还是未检查异常,它仍会显示出来。 那么,如何向客户表明这种失败?

3)检查异常可以培养更强大的程序

有一段时间,Oak和最早的Java版本没有检查异常。 异常处理是建议性的,这是一个不安全的世界。 我们的小组(Jim Waldo和我特别是:-)建议编译器检查异常。 吉姆在他的论点中非常有说服力,讲述了一个强大的代码将占据统治地位的世界。 经过一番考虑后,Java被重组以检查异常。 只有那些没有恢复或反映应用程序错误的异常才会被取消选中(例如,分别为OutOfMemoryError,NullPointerException)。 世界再次安全。

想象一下,当Java API和编译器中的许多异常从未经检查变为检查时,Java工程师会感到惊讶,并且编译器强制执行区分,他们发现了实现中的错误! 因此,处理错误条件的最佳努力,无论出于好意,都不够好。 那个编译器对某些东西很有用:-)

4)RemoteException应该是一个经过检查的异常

好的,所以回到正轨。 由于RemoteException在RPC调用中是生命中的事实(参见#1,#2),并且检查了异常强制您编写安全代码(#3),我们认为将RemoteException作为已检查的异常是一个好主意。 编写健壮的分布式程序是很困难的,没有编译器可以帮助您处理异常。

因此,有些人可能认为RemoteException就像OutOfMemoryError; 如果远程呼叫失败,你的程序应该会死掉。 我不同意这一点。 是的,在某些情况下,RemoteException无法恢复; 但是如果您正在编写可靠的分布式程序,那么您的客户端需要捕获故障并进行适当的重试。 也许您需要联系其他服务器,或中止某种事务。 如果未处理RemoteException,它将渗透并崩溃您的客户端(yuk)。

其他人已经声明在本地案例和远程案例中都使用了一些远程接口,并且客户端不应该在本地案例中处理异常,因此RemoteException不应该在throws子句和处理中它不应该是强制性的。 现在,如果我们允许远程接口方法省略RemoteException并且有一个“rmic”开关来生成会抛出未经检查的RemoteException的存根,那么客户端没有选择。 异常处理的决定应保留在客户端。 如果定义一个仅抛出未经检查的异常的接口,则永远不能编写希望编译器帮助处理这些异常的客户端。 我们已经从上面的例子中看到,检查异常会产生健壮的代码。

另一个突然出现的问题是,开发人员需要简单地翻译本地接口并将其用作远程接口。 这可能适用于一小部分情况,但如果接口的设计并未考虑并发性和部分故障以及呼叫延迟,则接口捕获的协议可能不适合在分布式情况下使用。 是否在这些操作中传递了足够的信息以使操作具有幂等性? 也许,但很可能不是。

将RemoteException放在每个throws子句中可能看起来很痛苦,但是编写健壮的分布式应用程序需要付出代价。

- Ann Wollrath

NullPointerExceptionRemoteException有更多的可能性。 任何调用对象上的方法的代码(实际上几乎都是任何Java代码)都可能抛出NullPointerException 只有RMI代码才能抛出RemoteException 这是“所有代码”的一小部分。

在编写RMI库时,设计人员决定使客户端代码期望处理这些异常。 考虑到远程代码执行的性质,我认为这是合理的。

我理解的方式是:

  • 对于可以阻止的事情,抛出RuntimeExceptions。
  • 对于那些不可避免但可以恢复的事情,会抛出例外情况
  • 对于那些不可避免且无法恢复的事情,会抛出错误。

例如,始终可以避免NullPointerExceptions,因此是未经检查的异常。 当网络出现故障时可能会发生RemoteException,这在方法调用之前无法合理地阻止,因此会被检查。

除了仅应用于java.rmijavax.rmi包(及其子包)中的代码的RemoteException之外, RemoteException是一种IOException ,就像SocketException是......并且所有IOException都是经过检查的异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM