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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2884836/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:17:11  来源:igfitidea点击:

Why NullPointerException is a runtime exception and RemoteException not?

javaexceptionruntimeexception

提问by Tom Brito

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. But this happens with RemoteException.

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

And a possible reason because RemoteException is not a runtime exception, is to tell it client to treat the exception. But every method in a remote environment need throws it, so there is no difference of throwing NullPointerException.

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

Speculations? Was I clear?

猜测?我说清楚了吗?

回答by Pascal Thivent

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). This is extracted from this messagefrom the RMI-USERS archives (message from Jan 1999):

我不会讨论这个决定,我只会引用 Ann Wollrath(他领导 Java RMI 的设计和实现)对这个决定的解释。这是从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. 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.

cheers,

-- Ann


I'd like to address the rationale for making RemoteException a checked Exception, rather than a RuntimeException.

1) networks aren't reliable

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. 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. 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.

2) RPC failure can't be hidden from the client

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

There was a time when Oak and the earliest version of Java did not have checked exceptions. 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 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. Only those exceptions for which there was no recovery or reflect application errors would be unchecked (e.g., OutOfMemoryError, NullPointerException respectively). 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! 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

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. 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; 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; 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).

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. 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 clienthas nochoice in the matter. 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.

-- Ann Wollrath

将 RemoteException 设为已检查异常并要求远程方法在其 throws 子句中列出异常的决定并不是宗教性的。该决定基于如何使分布式计算可靠。这个问题每隔一段时间就会出现在我们的用户列表中。我有一个详细的回复,我不久前发布了。如果您有兴趣,这里是。我在 rmi-users 档案中找不到它,所以我把它包含在下面。

干杯,

——安


我想说明将 RemoteException 设为已检查异常而不是 RuntimeException 的基本原理。

1)网络不可靠

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

RMI 并非旨在仅处理单个机器崩溃时整个网络崩溃的有限情况。这样的网络被认为是可靠的,要么一切正常,要么一切都失败——没有部分故障。RMI 面向更一般的受众。

2) RPC 失败无法对客户端隐藏

部分失败是分布式编程的一个事实;这些故障无法隐藏在程序中。客户端出现失败,无论是检查异常还是未检查异常,它仍然显示。那么,应该如何向客户端指示此类故障呢?

3) 检查异常促进更健壮的程序

曾经有一段时间,Oak 和最早的 Java 版本没有检查异常。异常处理是建议性的,这是一个不安全的世界。是我们的团队(特别是 Jim Waldo 和我 :-)建议编译器检查异常。Jim 在他的论点中非常有说服力,讲述了一个健壮的代码将统治的世界。经过一番考虑,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 子句中似乎很痛苦,但这是编写健壮的分布式应用程序所要付出的代价。

——安·沃尔拉斯

回答by Bill the Lizard

There is vastly more potential for NullPointerExceptionthan RemoteException. Any code that calls a method on an object (meaning practically any Java code at all) could potentially throw a NullPointerException. Only RMI code can throw a RemoteException. This is a tiny subset of "all code."

NullPointerException比 的潜力要大得多RemoteException。任何调用对象方法的代码(实际上意味着任何 Java 代码)都可能抛出NullPointerException. 只有 RMI 代码可以抛出RemoteException. 这是“所有代码”的一个很小的子集。

When writing the RMI libraries, the designers decided to make the client code expect to deal with these exceptions. Considering the nature of remote code execution, I think that's reasonable.

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

回答by Steve

The way I understand it is:

我的理解方式是:

  • RuntimeExceptions are thrown for things that were preventable.
  • Exceptions are thrown for things that were unpreventable but recoverable
  • Errors are thrown for things that were unpreventable and unrecoverable.
  • 对于可预防的事情,会抛出 RuntimeExceptions。
  • 对于不可预防但可恢复的事情抛出异常
  • 对于不可预防和不可恢复的事情,会抛出错误。

For example, NullPointerExceptions can always be avoided and are therefore unchecked exceptions. A RemoteException could occur when there is a network failure, which cannot be reasonably prevented before the method call and therefore is checked.

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

回答by Powerlord

Besides RemoteExceptiononly applying to code from java.rmiand javax.rmipackages (and their subpackages), RemoteExceptionis a type of IOException, much like SocketExceptionis... and all IOExceptions are checked exceptions.

除了RemoteException仅适用于来自java.rmijavax.rmi包(及其子包)的代码之外,RemoteException是一种IOException,很像SocketExceptionis... 并且所有IOExceptions 都是已检查的异常。