简体   繁体   English

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

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

A possible reason because a NullPointerException is a runtime exception is because every method can throw it, so every method would need to have a "throws NullPointerException", and would be ugly. 可能的原因是因为NullPointerException是一个运行时异常是因为每个方法都可以抛出它,因此每个方法都需要“抛出NullPointerException”,并且会很难看。 But this happens with RemoteException. 但这会发生在RemoteException上。

And a possible reason because RemoteException is not a runtime exception, is to tell it client to treat the exception. 并且可能的原因是因为RemoteException不是运行时异常,就是告诉客户端处理异常。 But every method in a remote environment need throws it, so there is no difference of throwing NullPointerException. 但是远程环境中的每个方法都需要抛出它,因此抛出NullPointerException没有区别。

Speculations? 猜测? Was I clear? 我清楚了吗?

I won't discuss the decision, I'll just quote the explanation of the decision from Ann Wollrath (who lead the design and implementation of Java RMI). 我不会讨论这个决定,我只是引用Ann Wollrath(他领导Java RMI的设计和实现)的决定的解释。 This is extracted from this message from the RMI-USERS archives (message from Jan 1999): 这是从RMI-USERS档案中的这条消息中提取的(1999年1月的消息):

The decision to make RemoteException a checked exception and requiring remote methods to list the exception in its throws clause is not a religious one. 将RemoteException作为一个已检查的异常并要求远程方法在其throws子句中列出异常的决定并不是宗教性的。 The decision is based on how to make distributed computing reliable. 该决定基于如何使分布式计算可靠。 This question comes up every once in a while on our users list. 这个问题偶尔出现在我们的用户列表中。 I have a detailed response that I posted a while ago. 我刚才发布了一个详细的回复。 Here it is if you are interested. 如果您有兴趣,请点击这里。 I couldn't find it in the rmi-users archive, so I included it below. 我在rmi-users存档中找不到它,所以我将其包含在下面。

cheers, 干杯,

-- Ann - 安


I'd like to address the rationale for making RemoteException a checked Exception, rather than a RuntimeException. 我想解决使RemoteException成为检查异常而不是RuntimeException的基本原理。

1) networks aren't reliable 1)网络不可靠

I wish that they were, but in fact, they're not. 我希望他们是,但事实上,他们不是。 Every network has transient failures. 每个网络都有短暂的故障。 You can build in network redundancy, but the fact is that most networks don't have that. 您可以构建网络冗余,但事实是大多数网络都没有。 Intranets have transient failures, as does the Internet. 内联网有短暂的故障,互联网也是如此。 So, every RPC made, is subject to a failure. 因此,每个RPC都会出现故障。 The types of failures may not have anything to do with the "network", per se; 失败的类型本身可能与“网络”无关; if your server runs out of file descriptors, your client will get a connect exception. 如果您的服务器用完文件描述符,您的客户端将获得连接异常。 This isn't a network failure, in the sense of the network being broken; 从网络被破坏的意义上讲,这不是网络故障; your server is in a transient state of being resource starved. 您的服务器处于资源匮乏的暂时状态。

RMI is not designed to only handle the limited case that the whole network crashes when a single machine crashes. RMI的目的不仅仅是处理单个机器崩溃时整个网络崩溃的有限情况。 Such a network would be considered reliable, either everything is up or everything is down--there is no partial failure. 这样的网络将被认为是可靠的,无论是一切都结束还是一切都失败了 - 没有部分失败。 RMI is targetted for a more general audience. RMI针对更广泛的受众。

2) RPC failure can't be hidden from the client 2)无法从客户端隐藏RPC故障

Partial failure is a fact of distributed programming; 部分失败是分布式编程的事实; these failures can't be hidden to the program. 这些失败不能隐藏到程序中。 A failure shows up in the client, whether the exception is checked or unchecked exception, it still shows up. 客户端出现故障,无论是检查异常还是未检查异常,它仍会显示出来。 So, how should such failures be indicated to the client? 那么,如何向客户表明这种失败?

3) checked exceptions foster more robust programs 3)检查异常可以培养更强大的程序

There was a time when Oak and the earliest version of Java did not have checked exceptions. 有一段时间,Oak和最早的Java版本没有检查异常。 Exception handling was advisory, and it was an unsafe world out there. 异常处理是建议性的,这是一个不安全的世界。 It was our group (Jim Waldo and me in particular :-) that recommended that there be exceptions checked by the compiler. 我们的小组(Jim Waldo和我特别是:-)建议编译器检查异常。 Jim was quite persuasive in his arguments, telling of a world where robust code would reign. 吉姆在他的论点中非常有说服力,讲述了一个强大的代码将占据统治地位的世界。 After some consideration, Java was retooled to have checked exceptions. 经过一番考虑后,Java被重组以检查异常。 Only those exceptions for which there was no recovery or reflect application errors would be unchecked (eg, OutOfMemoryError, NullPointerException respectively). 只有那些没有恢复或反映应用程序错误的异常才会被取消选中(例如,分别为OutOfMemoryError,NullPointerException)。 And the world was safe again. 世界再次安全。

Imagine the Java engineers' surprise when many exceptions in the Java API and compiler were changed from unchecked to checked, and the compiler enforced the distinction, they uncovered bugs in the implementations! 想象一下,当Java API和编译器中的许多异常从未经检查变为检查时,Java工程师会感到惊讶,并且编译器强制执行区分,他们发现了实现中的错误! So, the best efforts at handling error conditions, however well intentioned, was not good enough. 因此,处理错误条件的最佳努力,无论出于好意,都不够好。 That compiler is useful for something :-) 那个编译器对某些东西很有用:-)

4) RemoteException should be a checked exception 4)RemoteException应该是一个经过检查的异常

Ok, so back on track here. 好的,所以回到正轨。 Since a RemoteException is a fact of life in a RPC call (see #1, #2) and checked exceptions force you to write safe code (#3), we thought that making RemoteException a checked exception was a good idea. 由于RemoteException在RPC调用中是生命中的事实(参见#1,#2),并且检查了异常强制您编写安全代码(#3),我们认为将RemoteException作为已检查的异常是一个好主意。 Writing robust distributed programs is hard enough, without having the compiler to help you with exceptions. 编写健壮的分布式程序是很困难的,没有编译器可以帮助您处理异常。

So, some might argue that a RemoteException is a like an OutOfMemoryError; 因此,有些人可能认为RemoteException就像OutOfMemoryError; your program should fall over dead if a remote call fails. 如果远程呼叫失败,你的程序应该会死掉。 I disagree with this point. 我不同意这一点。 Yes, in some cases, there is no recovery from a RemoteException; 是的,在某些情况下,RemoteException无法恢复; but if you are writing a reliable distributed program, your client needs to catch failures and retry appropriately. 但是如果您正在编写可靠的分布式程序,那么您的客户端需要捕获故障并进行适当的重试。 Perhaps you need to contact another server, or abort a transaction of some sort. 也许您需要联系其他服务器,或中止某种事务。 If the RemoteException is not handled, it will percolate up and crash your client (yuk). 如果未处理RemoteException,它将渗透并崩溃您的客户端(yuk)。

Others have stated that there are some remote interfaces that are used in both the local case and the remote case and the client should not have to deal with the exceptions in the local case, so RemoteException should not have to be in a throws clause and handling it should not be mandatory. 其他人已经声明在本地案例和远程案例中都使用了一些远程接口,并且客户端不应该在本地案例中处理异常,因此RemoteException不应该在throws子句和处理中它不应该是强制性的。 Now, if we allowed remote interface methods to omit RemoteException and had an "rmic" switch to generate stubs that would throw an unchecked RemoteException, the client has no choice in the matter. 现在,如果我们允许远程接口方法省略RemoteException并且有一个“rmic”开关来生成会抛出未经检查的RemoteException的存根,那么客户端没有选择。 The decision of exception handling should remain with the client. 异常处理的决定应保留在客户端。 If you define an interface that only throws unchecked exceptions you can never write a client that wants compiler help in dealing with those exceptions. 如果定义一个仅抛出未经检查的异常的接口,则永远不能编写希望编译器帮助处理这些异常的客户端。 We have already seen from the above example that checked exceptions fosters robust code. 我们已经从上面的例子中看到,检查异常会产生健壮的代码。

Another issue that has popped up now and again is that developers need to simply translate local interfaces and use them as remote interfaces. 另一个突然出现的问题是,开发人员需要简单地翻译本地接口并将其用作远程接口。 This may work for a small set of cases, but if the interface was not designed with concurrency and partial failure and call latency in mind, the protocol captured by the interface may not be appropriate to use in the distributed case. 这可能适用于一小部分情况,但如果接口的设计并未考虑并发性和部分故障以及呼叫延迟,则接口捕获的协议可能不适合在分布式情况下使用。 Is enough information passed in those operations to make the operations idempotent? 是否在这些操作中传递了足够的信息以使操作具有幂等性? Perhaps, but most likely not. 也许,但很可能不是。

Putting RemoteException in every throws clause may seem like a pain, but its the price to pay for writing robust distributed applications. 将RemoteException放在每个throws子句中可能看起来很痛苦,但是编写健壮的分布式应用程序需要付出代价。

-- Ann Wollrath - Ann Wollrath

There is vastly more potential for NullPointerException than RemoteException . NullPointerExceptionRemoteException有更多的可能性。 Any code that calls a method on an object (meaning practically any Java code at all) could potentially throw a NullPointerException . 任何调用对象上的方法的代码(实际上几乎都是任何Java代码)都可能抛出NullPointerException Only RMI code can throw a RemoteException . 只有RMI代码才能抛出RemoteException This is a tiny subset of "all code." 这是“所有代码”的一小部分。

When writing the RMI libraries, the designers decided to make the client code expect to deal with these exceptions. 在编写RMI库时,设计人员决定使客户端代码期望处理这些异常。 Considering the nature of remote code execution, I think that's reasonable. 考虑到远程代码执行的性质,我认为这是合理的。

The way I understand it is: 我理解的方式是:

  • RuntimeExceptions are thrown for things that were preventable. 对于可以阻止的事情,抛出RuntimeExceptions。
  • Exceptions are thrown for things that were unpreventable but recoverable 对于那些不可避免但可以恢复的事情,会抛出例外情况
  • Errors are thrown for things that were unpreventable and unrecoverable. 对于那些不可避免且无法恢复的事情,会抛出错误。

For example, NullPointerExceptions can always be avoided and are therefore unchecked exceptions. 例如,始终可以避免NullPointerExceptions,因此是未经检查的异常。 A RemoteException could occur when there is a network failure, which cannot be reasonably prevented before the method call and therefore is checked. 当网络出现故障时可能会发生RemoteException,这在方法调用之前无法合理地阻止,因此会被检查。

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

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

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