Java 8 getter 应该返回可选类型吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26327957/
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
Should Java 8 getters return optional type?
提问by leonprou
Optional
type introduced in Java 8 is a new thing for many developers.
Optional
Java 8 中引入的类型对许多开发人员来说是一个新事物。
Is a getter method returning Optional<Foo>
type in place of the classic Foo
a good practice? Assume that the value can be null
.
返回Optional<Foo>
类型代替经典的 getter 方法是一个Foo
好习惯吗?假设该值可以是null
。
采纳答案by Brian Goetz
Of course, people will do what they want. But we did have a clear intention when adding this feature, and it was notto be a general purpose Maybe type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result", and using null
for such was overwhelmingly likely to cause errors.
当然,人们会做他们想做的。但是我们在添加这个功能时确实有一个明确的意图,它不是一个通用的 Maybe 类型,就像很多人希望我们这样做的那样。我们的目的是为库方法返回类型提供一种有限的机制,在这种机制中需要有一种明确的方式来表示“无结果”,而使用null
for 则极有可能导致错误。
For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list. You should almost never use it as a field of something or a method parameter.
例如,您可能永远不应该将它用于返回结果数组或结果列表的内容;而是返回一个空数组或列表。您几乎不应该将它用作某物的字段或方法参数。
I think routinely using it as a return value for getters would definitely be over-use.
我认为经常使用它作为 getter 的返回值肯定会被过度使用。
There's nothing wrongwith Optional that it should be avoided, it's just not what many people wish it were, and accordingly we were fairly concerned about the risk of zealous over-use.
Optional 应该避免它并没有错,只是它不是很多人希望的那样,因此我们相当担心过度使用的风险。
(Public service announcement: NEVERcall Optional.get
unless you can prove it will never be null; instead use one of the safe methods like orElse
or ifPresent
. In retrospect, we should have called get
something like getOrElseThrowNoSuchElementException
or something that made it far clearer that this was a highly dangerous method that undermined the whole purpose of Optional
in the first place. Lesson learned. (UPDATE: Java 10 has Optional.orElseThrow()
, which is semantically equivalent to get()
, but whose name is more appropriate.))
(公共服务公告:除非你能证明它永远不会为空,否则永远不要调用Optional.get
;而是使用安全方法之一,如orElse
或ifPresent
。回想起来,我们应该调用get
类似getOrElseThrowNoSuchElementException
或类似的东西,使之更清楚地表明这是一种非常危险的方法这首先破坏了 的整个目的Optional
。吸取了教训。(更新:Java 10 有Optional.orElseThrow()
,在语义上等同于get()
,但其名称更合适。))
回答by Claas Wilke
I'd say in general its a good idea to use the optional type for return values that can be nullable. However, w.r.t. to frameworks I assume that replacing classical getters with optional types will cause a lot of trouble when working with frameworks (e.g., Hibernate) that rely on coding conventions for getters and setters.
我会说一般来说,将可选类型用于可以为空的返回值是一个好主意。然而,对于框架,我认为在使用依赖于 getter 和 setter 的编码约定的框架(例如,Hibernate)时,用可选类型替换经典 getter 会导致很多麻烦。
回答by Justin
After doing a bit of research of my own, I've come across a number of things that might suggest when this is appropriate. The most authoritative being the following quote from an Oracle article:
在我自己做了一些研究之后,我发现了一些可能会在适当的时候提出建议的事情。最权威的是 Oracle 文章中的以下引用:
"It is important to note that the intention of the Optional class is not to replace every single null reference. Instead, its purpose is to help design more-comprehensible APIsso that by just reading the signature of a method, you can tell whether you can expect an optional value. This forces you to actively unwrap an Optional to deal with the absence of a value."- Tired of Null Pointer Exceptions? Consider Using Java SE 8's Optional!
“需要注意的是,Optional 类的目的不是替换每一个空引用。相反,它的目的是帮助设计更易于理解的 API,以便通过阅读方法的签名,您可以判断您是否可以期待一个可选值。这迫使你主动打开一个 Optional 来处理没有值的情况。” -厌倦了空指针异常?考虑使用 Java SE 8 的 Optional!
I also found this excerpt from Java 8 Optional: How to use it
我还从Java 8 Optional: How to use it 中找到了这段摘录
"Optional is not meant to be used in these contexts, as it won't buy us anything:
- in the domain model layer (not serializable)
- in DTOs (same reason)
- in input parameters of methods
- in constructor parameters"
“Optional 不打算在这些情况下使用,因为它不会给我们买任何东西:
- 在域模型层(不可序列化)
- 在 DTO 中(同样的原因)
- 在方法的输入参数中
- 在构造函数参数中”
Which also seems to raise some valid points.
这似乎也提出了一些有效的观点。
I wasn't able to find any negative connotations or red flags to suggest that Optional
should be avoided. I think the general idea is, if it's helpful or improves the usability of your API, use it.
我找不到任何负面含义或危险信号来表明Optional
应该避免这种情况。我认为一般的想法是,如果它有帮助或提高了 API 的可用性,请使用它。
回答by Mark
Ifyou are using modern serializers and other frameworks that understand Optional
then I have found these guidelineswork well when writing Entity
beans and domain layers:
如果您正在使用现代序列化程序和其他理解的框架,Optional
那么我发现这些指南在编写Entity
bean 和域层时效果很好:
- If the serialization layer (usually a DB) allows a
null
value for a cell in columnBAR
in tableFOO
, then the getterFoo.getBar()
can returnOptional
indicating to the developer that this value may reasonably be expected to be null and they should handle this. If the DB guarantees the value will not be null then the getter should notwrap this in anOptional
. Foo.bar
should beprivate
and notbeOptional
. There's really no reason for it to beOptional
if it isprivate
.- The setter
Foo.setBar(String bar)
should take the type ofbar
and notOptional
. If it's OK to use anull
argument then state this in the JavaDoc comment. If it's not OK to usenull
anIllegalArgumentException
or some appropriate business logic is, IMHO, more appropriate. - Constructors don't need
Optional
arguments (for reasons similar to point 3). Generally I only include arguments in the constructor that mustbe non-null in the serialization database.
- 如果序列化层(通常是 DB)允许table
null
中 columnBAR
中的单元格的值FOO
,则 getterFoo.getBar()
可以返回Optional
向开发人员指示该值可能合理地预期为 null 并且他们应该处理这个。如果DB保证值不为空,则吸气应该不会在包装这个Optional
。 Foo.bar
应该是private
和不是Optional
。Optional
如果是的话,真的没有理由这样做private
。- setter
Foo.setBar(String bar)
应该采用 ofbar
而不是Optional
。如果可以使用null
参数,请在 JavaDoc 注释中说明。如果不能使用null
一个IllegalArgumentException
或一些适当的业务逻辑,恕我直言,更合适。 - 构造函数不需要
Optional
参数(原因类似于第 3 点)。通常我只在构造函数中包含序列化数据库中必须为非空的参数。
To make the above more efficient, you might want to edit your IDE templates for generating getters and corresponding templates for toString()
, equals(Obj o)
etc. or use fields directly for those (most IDE generators already deal with nulls).
为了使上述更有效,你可能要编辑您的IDE模板生成getter和相应的模板toString()
,equals(Obj o)
直接等,或使用领域的那些(最IDE发电机已处理空值)。
回答by MiguelMunoz
The reason Optional
was added to Java is because this:
Optional
加入Java的原因是因为:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
is cleaner than this:
比这更干净:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
My point is that Optional was written to support functional programming, which was added to Java at the same time. (The example comes courtesy of a blog by Brian Goetz. A better example might use the orElse()
method, since this code will throw an exception anyway, but you get the picture.)
我的观点是Optional 是为了支持函数式编程而编写的,它同时被添加到 Java 中。(这个例子来自Brian Goetz的博客。一个更好的例子可能会使用这个orElse()
方法,因为无论如何这段代码都会抛出一个异常,但你得到了图片。)
But now, people are using Optional for a very different reason. They're using it to address a flaw in the language design. The flaw is this: There's no way to specify which of an API's parameters and return values are allowed to be null. It may be mentioned in the javadocs, but most developers don't even write javadocs for their code, and not many will check the javadocs as they write. So this leads to a lot of code that always checks for null values before using them, even though they often can't possibly be null because they were already validated repeatedly nine or ten times up the call stack.
但是现在,人们出于非常不同的原因使用 Optional。他们正在使用它来解决语言设计中的缺陷。缺陷在于:无法指定 API 的哪些参数和返回值允许为空。它可能在 javadoc 中提到,但大多数开发人员甚至不会为他们的代码编写 javadoc,并且很少有人会在编写时检查 javadoc。所以这导致很多代码在使用它们之前总是检查空值,即使它们通常不可能为空,因为它们已经在调用堆栈上反复验证了九次或十次。
I think there was a real thirst to solve this flaw, because so many people who saw the new Optional class assumed its purpose was to add clarity to APIs. Which is why people ask questions like "should getters return Optionals?" No, they probably shouldn't, unless you expect the getter to be used in functional programming, which is very unlikely. In fact, if you look at where Optional is used in the Java API, it's mainly in the Stream classes, which are the core of functional programming. (I haven't checked very thoroughly, but the Stream classes might be the onlyplace they're used.)
我认为确实有解决这个缺陷的渴望,因为看到新的 Optional 类的很多人都认为它的目的是增加 API 的清晰度。这就是为什么人们会问“getter 应该返回 Optionals 之类的问题吗?” 不,他们可能不应该,除非您希望在函数式编程中使用 getter,这不太可能。事实上,如果你看一下Java API 中Optional 使用的地方,主要是在Stream 类中,它们是函数式编程的核心。(我没有仔细检查过,但 Stream 类可能是唯一使用它们的地方。)
If you do plan to use a getter in a bit of functional code, it might be a good idea to have a standard getter and a second one that returns Optional.
如果您确实打算在一些函数式代码中使用 getter,那么拥有一个标准的 getter 和返回 Optional 的第二个 getter 可能是个好主意。
Oh, and if you need your class to be serializable, you should absolutely not use Optional.
哦,如果你需要你的类可序列化,你绝对不应该使用 Optional。
Optionals are a very bad solution to the API flaw because a) they're very verbose, and b) They were never intended to solve that problem in the first place.
Optionals 是 API 缺陷的一个非常糟糕的解决方案,因为 a) 它们非常冗长,b) 它们一开始就没有打算解决这个问题。
A much better solution to the API flaw is the Nullness Checker. This is an annotation processor that lets you specify which parameters and return values are allowed to be null by annotating them with @Nullable. This way, the compiler can scan the code and figure out if a value that can actually be null is being passed to a value where null is not allowed. By default, it assumes nothing is allowed to be null unless it's annotated so. This way, you don't have to worry about null values. Passing a null value to a parameter will result in a compiler error. Testing an object for null that can't be null produces a compiler warning. The effect of this is to change NullPointerException from a runtime error to a compile-time error.
API 缺陷的一个更好的解决方案是Nullness Checker。这是一个注解处理器,允许您通过使用 @Nullable 进行注解来指定允许哪些参数和返回值为空。这样,编译器可以扫描代码并确定是否将实际上可以为 null 的值传递给不允许为 null 的值。默认情况下,它假定任何东西都不允许为空,除非它被注释了。这样,您不必担心空值。将空值传递给参数将导致编译器错误。测试不能为 null 的 null 对象会产生编译器警告。这样做的效果是将 NullPointerException 从运行时错误更改为编译时错误。
This changes everything.
这改变了一切。
As for your getters, don't use Optional. And try to design your classes so none of the members can possibly be null. And maybe try adding the Nullness Checker to your project and declaring your getters and setter parameters @Nullable if they need it. I've only done this with new projects. It probably produces a lot of warnings in existing projects written with lots of superfluous tests for null, so it might be tough to retrofit. But it will also catch a lot of bugs. I love it. My code is much cleaner and more reliable because of it.
至于你的吸气剂,不要使用 Optional。并尝试设计您的类,以便所有成员都不可能为空。也许尝试将 Nullness Checker 添加到您的项目中,并在需要时声明您的 getter 和 setter 参数 @Nullable。我只在新项目中做到了这一点。它可能会在现有项目中产生大量警告,这些项目使用大量多余的 null 测试编写,因此可能难以改造。但它也会捕获很多错误。我喜欢它。因为它,我的代码更简洁、更可靠。
(There is also a new language that addresses this. Kotlin, which compiles to Java byte code, allows you to specify if an object may be null when you declare it. It's a cleaner approach.)
(还有一种新语言可以解决这个问题。Kotlin 编译为 Java 字节码,允许您在声明对象时指定它是否可以为 null。这是一种更简洁的方法。)
Addendum to Original Post (version 2)
原始帖子的附录(第 2 版)
After giving it a lot of thought, I have reluctantly come to the conclusion that it's acceptable to return Optional on one condition: That the value retrieved might actually be null. I have seen a lot of code where people routinely return Optional from getters that can't possibly return null. I see this as a very bad coding practice that only adds complexity to the code, which makes bugs more likely. But when the returned value might actually be null, go ahead and wrap it inside an Optional.
经过深思熟虑,我不情愿地得出结论,在一个条件下返回 Optional 是可以接受的:检索到的值实际上可能为 null。我见过很多代码,其中人们经常从不可能返回 null 的 getter 返回 Optional。我认为这是一种非常糟糕的编码实践,它只会增加代码的复杂性,从而更容易出现错误。但是当返回的值实际上可能为 null 时,请继续将其包装在 Optional 中。
Keep in mind that methods that are designed for functional programming, and that require a function reference, will (and should) be written in two forms, one of which uses Optional. For example, Optional.map()
and Optional.flatMap()
both take function references. The first takes a reference to an ordinary getter, and the second takes one that returns Optional. So you're not doing anyone a favor by return an Optional where the value can't be null.
请记住,为函数式编程而设计且需要函数引用的方法将(并且应该)以两种形式编写,其中一种使用 Optional。例如,Optional.map()
并且Optional.flatMap()
都接受函数引用。第一个引用一个普通的 getter,第二个引用一个返回 Optional 的。因此,您不会通过返回值不能为空的 Optional 来帮助任何人。
Having said all that, I still see the approach used by the Nullness Checkeris the best way to deal with nulls, since they turn NullPointerExceptions from runtime bugs to compile time errors.
尽管如此,我仍然认为Nullness Checker使用的方法是处理空值的最佳方法,因为它们将 NullPointerExceptions 从运行时错误转变为编译时错误。