返回 NULL 的替代方案
/**
* Returns the foo with the matching id in this list
*
* @param id the id of the foo to return
* @return the foo with the matching id in this list
*/
public Foo getFoo(int id)
{
for (Foo foo : list)
{
if (foo.getID() == id)
{
return foo;
}
}
return null;
}
当找不到 foo
时,我应该抛出
一个异常
,而不是返回null
吗?这重要吗?关于这个主题是否有“最佳实践”习语?顺便说一句,我知道我的例子有点做作,但我希望你明白......
谢谢。
编辑
更改了代码以根据id获取Foo
,以更好地说明现实世界的场景。
/**
* Returns the foo with the matching id in this list
*
* @param id the id of the foo to return
* @return the foo with the matching id in this list
*/
public Foo getFoo(int id)
{
for (Foo foo : list)
{
if (foo.getID() == id)
{
return foo;
}
}
return null;
}
Instead of returning null
when foo
is not found, should I throw
an exception
? Does it matter, and is there a "best practices" idiom on the subject? By the way, I know my example is a bit contrived, but I hope you get the idea...
Thanks.
EDIT
Changed code to get Foo
based on id to better illustrate a real-world scenario.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
返回
null
不仅处理起来更简单,而且性能也更好。必须使用异常来处理异常情况。Returning
null
is not only more simple to handle, performs better too. The exceptions must be used to handle exceptional cases.我想说这取决于你的方法的语义。
foo
几乎总能在列表中找到吗? (例如,如果它是保存有限数量对象的缓存)。如果是这样,那么找不到可能意味着出现了问题 - 例如,某些应用程序初始化失败,或者密钥无效 - 并且异常可能是合理的。然而,在大多数情况下,我会返回
null
。也许客户端知道该对象可能不存在并且具有编码逻辑来处理这种情况;如果您使用异常,该代码将更难以阅读、理解和维护。一些 API 实际上提供了两种方法:可能返回 null 的
find
方法,以及引发异常的get
或load
方法。嗯...如有疑问,请错误地支持 null :)
I'd say it depends on the semantics of your method.
Will
foo
be almost always found in the list? (for example, if it is a cache that holds a finite amount of objects). If so, then not being found might mean something has gone wrong -- some app initialization failed, for example, or the key is invalid -- and an exception might be justifiable.In most circumstances, however, I'd return
null
. Maybe the client knows the object might not be there and has coded logic to handle that case; if you used an exception, that code would be much harder to read, understand, and maintain.Some APIs actually provide two methods: a
find
method that may return null, and aget
orload
method that throws an exception.Hmmm... when in doubt, err in favor of null :)
如果它被记录为有效结果,则返回 null 就可以了。
另一种选择是空对象模式。也就是说 - 一个没有任何数据的
Foo
实例:并返回它。
Returning
null
is fine, if it is documented as a valid result.Another option is the null-object pattern. That is - an instance of
Foo
that doesn't have any data:and return it instead.
我更喜欢返回
null
。这是从方法返回的完美结果,并且调用该方法的代码应该适当地处理 null 值。这可能意味着在调用代码中抛出异常,但我不会在这个方法中这样做。这样,如果其他人想要调用您的方法,他们可以选择以与您不同的方式处理空值。如果你抛出异常,它可能会迫使另一个程序员以不同于他们预期的方式更改他们的代码。
当然,在某些情况下,如果某些内容为空(例如,连接对象或类似的东西,您实际上需要有一个值,那么抛出异常是有意义的,如果没有,则意味着某些内容是空的)错误的)。但是,根据经验,在大多数情况下返回 null 应该没问题。
I prefer returning
null
. This is a perfectly fine result to return from a method, and your code that calls the method should handle null values appropriately. That might mean throwing an exception in your calling code, but I wouldn't do it in this method.This way, if someone else wants to call your method down the line, they can handle null values differently than you if they choose. If you threw and exception it could potentially force another programmer to alter their code in a way different than what they intended.
Of course, there are some cases where it would make sense to throw an exception if something is null (like, a connection object or something like that, that you actually need to have a value and if you don't then that means something is wrong). But, as a rule of thumb, you should be fine returning null in most cases.
如果可以的话最好避免异常,但有时你就是做不到。在这种情况下,如果您在列表中存储了
null
会怎样?您无法区分“找到空值”和“找不到您想要的内容”之间的区别。有一种模式,称为选项类型,它在 Scala 中被大量使用。您要么返回一个包含该项目的容器,要么返回一个表示“我是空的”的类的容器。维基文章将提供更好的图片。
您还可以询问“该集合中是否存在此内容?”返回 bool 的方法,如果您没有先检查,则从上面的代码中抛出异常。
只是一条与您的实际问题完全无关的评论。如果您实现 equals,则仅当两个对象实际上被视为相等时才应返回 true。因此,上面的代码必须始终返回您传递给它的对象!
It's best to avoid exceptions if you can, but sometimes you just can't. In this case, what if you had stored
null
in the list? You can't tell the difference between 'found null' and 'could not find what you wanted'.There is a pattern, it's called Option Types and it's used a lot in Scala. You either return a container with the item, or a container of a class that says 'I'm empty'. The wiki article will give a better picture.
You could also have a 'does this exist in the collection?' method which returns a bool, then throw an exception from the above code for if you didn't check first.
And just a comment completely unrelated to your actual question. If you implement equals, it should only return true if the two objects are actually considered equal. Therefore the above code must always return the object you pass into it!
最好的做法是在 Javadoc 中声明,当未找到匹配项时,将返回
null
。另一种方法可能是返回一个可能为空(并且可能有多个)的匹配列表,但是我不喜欢这种方法。
另一种方法可能是返回 Foo 类型值的 NULL_FOO。
我宁愿只返回 null。
解决这个问题的一种方法是查看您将如何处理该值并丰富函数,以便返回的值在方法中使用而不是返回。例如,如果您要使用该值调用一个方法,只需在函数中调用它即可避免返回任何内容。
Best pactice would be to say in the Javadoc that
null
is return when no match is found.Another approach might be to return a List of matches which could be empty (and could have more than one) However I don't like this approach.
Another approach might be to return a NULL_FOO of type Foo value.
I would prefer to just return null.
One way around this is to look at what are you going to do with the value and enrich the function so that the returned value is used in the method and not returned. e.g. if you are going to call a method with the value, just call it in the function which avoids the need to return anything.
这是一个老问题,但我没有找到番石榴的 可选 类以及 JDK 的 可选(来自 Java 8),具有相同的目的并具有更多功能。
这篇文章很好地概述了使用 guava 的Optional 的原因。我强烈推荐阅读它。
这是摘录:
我个人的观点(如果这很重要的话)是,在像 Java 这样已经很冗长的语言中,返回 null 并不是那么可怕。该方法的签名有时会尖叫可能存在某种空类型的结果,并且使用Optional无论如何都不会在语义方面添加任何内容。例如:
或者在通过键在映射中查找值的方法中。
如果调用这样的方法并对结果执行空检查,则很明显发生了什么(检查平行线或未找到键)。我倾向于返回 null 以免代码膨胀。
不过我总是会在 javadoc 中记录它。
This is an old question but I didn't find guava's Optional class mentioned here and also JDK's Optional (from Java 8) which serves the same purpose and has more functionality.
This article is a good overview on the reasons for using guava's Optional. I highly recommend reading it.
Here's an excerpt:
My personal opinion, if that matters at all, is that returning null is not so terrible in an already verbose language like Java. The signature of the method sometimes screams that there can be some sort of null kind of result and using Optional doesn't add anything in terms of semantics anyway. For example:
Or in a method that looks up a value in a map by key.
If one calls such a method and performs a null check on the result, it's pretty obvious what is going on (checking for parallel lines or key not found). I would favor returning null lest I bloat my code.
I would always document it in the javadoc though.
主要取决于场景。如果您的应用程序本身就是该方法的生产者和使用者,那么完全由您决定要做什么,否则您需要根据该方法的使用情况和客户需求来决定。
majory it depends on the scenarios. If your app is itself producer and consumer of this method then it is completly upto you to decide what to do, Else you need to decide based on usage of the method and Client needs.
返回
null
是完全可以接受的。我会进行额外的几十次击键,并在 JavaDoc 中记录返回null
的可能性。抛出已检查的异常意味着您必须在调用方法的任何地方尝试/捕获或重新抛出该异常。未经检查的异常,尤其是 NPE 以外的任何异常,都会让人们大吃一惊。
Returning
null
is perfectly acceptable. I would go the extra couple dozen keystrokes and document the possibility of returningnull
in the JavaDoc.Throwing checked exception means you have to try/catch or re-throw that exception everywhere your method gets called. An unchecked exception, especially anything other than an NPE, is going to catch people by surprise.
在本例中,由于您正在定义一个访问器,因此它应该返回 null。如果是另一种方法,该方法应保证非空响应,则异常会更合适。
不过,作为旁注,与其将示例方法称为 getter,不如将其命名为 Foo findFoo(Foo f) 之类的名称,因为您正在搜索而不仅仅是获取。
In this case, since you're defining an accessor, it should return null. If it were another method where this method should guarantee a non-null response, an exception would be more appropriate.
As a side note though, rather than calling the sample method a getter it might be more appropriate to name it something like
Foo findFoo(Foo f)
since you're searching rather than just getting.我认为这是一个品味问题,在这种情况下,它还取决于列表是否可能包含空值。如果列表可能包含 null 值,则 null 也将是有效的方法参数,并且您需要区分返回 null(例如传递、找到并返回 null)或告诉方法调用者传递的 null 值不是空值发现。
I think it's a matter of taste and in this case it also depends on if the list may contain null values. If the list may contain null values, null would also be a valid method argument and you would need to distinguish between returning null (e.g. null was passed, found and returned) or telling the method caller that the passed null value was not found.
这可能不会直接回答你的问题,但它来自我从 Stackoverflow 成员那里得到的关于类似主题的一些评论。
根据我的收集,当异常涉及给定方法的参数时,应该从方法中抛出异常。例如,接受 File 实例的方法将抛出 NullPointerException 或 IOException ,这遵循调用者和被调用者之间存在契约的想法,调用者应该发送有效的对象并在它们无效时处理它们
。决定是否处理前置条件和后置条件。您可以在方法的开头放置一个保护来处理参数,这会节省大量代码,但是,有些人认为这是一种不正确的方法,例如在验证中。 UI,应该提前完成
,如果意图是检索单个实例,那么返回一个空对象是完全有效的,这意味着当涉及到组时,没有找到或不存在对象。我认为约定只是返回一个空的集合/列表。
This might not answer your question directly but it comes from a few remarks I've gotten from Stackoverflow members on similar topics.
From what I gather, Exceptions should be thrown from a method when the Exception concerns a parameter given to the method. For example, a method accepting File instances would throw a NullPointerException or an IOException. This is following the idea that there's a contract between the caller and callee that the caller should sent valid objects and take care of them if they're invalid.
Also, you need to decide whether to handle pre- and postconditions. You can place a guard at the beginning of a method to handle parameters and this would save quite a bit of code. However, some view this as an incorrect approach in that some validation, say in a UI, should be done beforehand.
To finish off, it's perfectly valid to return a null object if the intent is to retrieve a a single instance. This is to paraphrase that an object was not found or doesn't exist. When it comes to groups of objects I think the convention is simply to return an empty Collection/List.
我想说这取决于您的应用程序以及如何使用该方法。
我同意这样的观点:异常应该用于异常条件,这是错误条件的超集。我还采用了 Spring/Hibernate 对未检查异常的偏好,这避免了繁琐的 try/catch 逻辑。
* 使用异常与返回 null 相比并没有太多性能开销。我刚刚做了一个快速测试,调用一个方法一百万次返回 null 需要 4ms,而调用另一个方法一百万次抛出异常只需要 535ms。
I'd say it depends on your app and how the method will be used.
I subscribe to the opinion that exceptions should be used for exceptional conditions, which is a superset of error conditions. I also have adopted Spring/Hibernate's preference for unchecked exceptions, which avoids burdensome try/catch logic.
* There is not much performance overhead from using exceptions vs. returning null. I just did a quick test, it takes 4ms to call a method a million times that returns null, and only 535ms to another method million times that throws an exception.
我在其他答案中没有读到的另一个观点如下:
list
是否包含Foo
的null
?如果是这种情况,人们将不知道是否找到了该 id,或者它是否与null
关联。在这种情况下:SearchResult
,它告诉您是否找到该对象、它的关联 ID、它的结果,或者如果未找到则没有结果);existsFoo(int id)
。每个解决方案都有其自身的问题,具体取决于使用的情况:
Exception
是异常;SearchResult
。包装器可以变得可变,但这会带来很多新的困难和问题;existsFoo
必须搜索列表,这使得了解键是否存在的成本增加了一倍。一般来说,我可以说:
SearchResult
;getFoo
是否只检查它是否为空(存在或不存在)?使用另一种方法,existsFoo
。Another point of view I haven't read in the other answers is the following:
Does the
list
containnull
's ofFoo
? If this is the case, one would not know whether the id was found, or whether it was associated withnull
. In this case:SearchResult
, which tells you if the object was found, it's associative id, it's result, or no result if it was not found);existsFoo(int id)
.Each solution has it's own problems, and it depends on the case which to use:
Exception
s are exceptional;SearchResult
, has to be allocated each time you'd like to retry a search. The wrapper can be made mutable, but this introduces a lot of new difficulties and problems;existsFoo
has to search the list which doubles the cost of knowing whether the key exists or not.Generally I can say:
IllegalArgumentException
;SearchResult
;getFoo
only checked whether it's null or not (it exists or not)? Use another method,existsFoo
.虽然我同意 null 编码是简单且容易的样板程序员调节,但它对于引入的复杂性几乎没有增加任何价值。始终假设非空引用可以使逻辑更清晰,代码稍微少一些——您仍然必须测试失败。
下面摘录的注释将帮助您避免陷入旧的方式。 ..
While I agree that coding for null is simple and easy boilerplate programmer conditioning, it adds little value for the complexity introduced. Always assuming non-null references makes for cleaner logic with slightly less code -- you still have to test for failure.
The annotation excerpt below will help you to not fall into the old ways...