Java 用于可选
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23454952/
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
Uses for Optional
提问by Will
Having been using Java 8 now for 6+ months or so, I'm pretty happy with the new API changes. One area I'm still not confident in is when to use Optional
. I seem to swing between wanting to use it everywhere something may be null
, and nowhere at all.
现在使用 Java 8 已经有 6 个多月的时间了,我对新的 API 更改感到非常满意。我仍然不确定的一个方面是何时使用Optional
. 我似乎在想要在任何可能存在的null
地方使用它和根本无处使用它之间摇摆不定。
There seem to be a lot of situations when I could use it, and I'm never sure if it adds benefits (readability / null safety) or just causes additional overhead.
似乎在很多情况下我都可以使用它,但我不确定它是否增加了好处(可读性/空值安全),或者只是导致额外的开销。
So, I have a few examples, and I'd be interested in the community's thoughts on whether Optional
is beneficial.
所以,我举了几个例子,我对社区关于是否Optional
有益的想法很感兴趣。
1 - As a public method return type when the method could return null
:
1 - 当方法可以返回时作为公共方法返回类型null
:
public Optional<Foo> findFoo(String id);
2 - As a method parameter when the param may be null
:
2 - 作为方法参数,当 param 可能是null
:
public Foo doSomething(String id, Optional<Bar> barOptional);
3 - As an optional member of a bean:
3 - 作为 bean 的可选成员:
public class Book {
private List<Pages> pages;
private Optional<Index> index;
}
4 - In Collections
:
4 - 在Collections
:
In general I don't think:
一般来说,我不认为:
List<Optional<Foo>>
adds anything - especially since one can use filter()
to remove null
values etc, but are there any good uses for Optional
in collections?
添加任何东西 - 特别是因为可以filter()
用来删除null
值等,但是Optional
在集合中有什么好的用途吗?
Any cases I've missed?
有没有我错过的案例?
采纳答案by Stuart Marks
The main point of Optional
is to provide a means for a function returning a value to indicate the absence of a return value. See this discussion. This allows the caller to continue a chain of fluent method calls.
的主要观点Optional
是为函数返回值提供一种方法来指示没有返回值。请参阅此讨论。这允许调用者继续一系列流畅的方法调用。
This most closely matches use case #1in the OP's question. Although, absence of a valueis a more precise formulation than nullsince something like IntStream.findFirst
could never return null.
这与OP 问题中的用例#1最匹配。虽然,没有值是比null更精确的表述,因为像IntStream.findFirst
这样的东西永远不会返回 null。
For use case #2, passing an optional argument to a method, this could be made to work, but it's rather clumsy. Suppose you have a method that takes a string followed by an optional second string. Accepting an Optional
as the second arg would result in code like this:
对于用例#2,将可选参数传递给方法,这可以起作用,但它相当笨拙。假设您有一个方法,它接受一个字符串,后跟一个可选的第二个字符串。接受一个Optional
作为第二个参数会导致这样的代码:
foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());
Even accepting null is nicer:
即使接受 null 也更好:
foo("bar", "baz");
foo("bar", null);
Probably the best is to have an overloaded method that accepts a single string argument and provides a default for the second:
可能最好的方法是拥有一个接受单个字符串参数并为第二个参数提供默认值的重载方法:
foo("bar", "baz");
foo("bar");
This does have limitations, but it's much nicer than either of the above.
这确实有局限性,但它比上述任何一个都要好得多。
Use cases #3and #4, having an Optional
in a class field or in a data structure, is considered a misuse of the API. First, it goes against the main design goal of Optional
as stated at the top. Second, it doesn't add any value.
用例#3和#4中,具有Optional
在一个类域或在一个数据结构中,被认为是API的滥用。首先,它违背Optional
了顶部所述的主要设计目标。其次,它没有增加任何价值。
There are three ways to deal with the absence of a value in an Optional
: to provide a substitute value, to call a function to provide a substitute value, or to throw an exception. If you're storing into a field, you'd do this at initialization or assignment time. If you're adding values into a list, as the OP mentioned, you have the additional choice of simply not adding the value, thereby "flattening" out absent values.
有三种方法可以处理 an 中没有值的情况Optional
:提供替代值、调用函数以提供替代值或抛出异常。如果要存储到字段中,则应在初始化或分配时执行此操作。如果您将值添加到列表中,正如 OP 所提到的,您可以选择不添加值,从而“展平”不存在的值。
I'm sure somebody could come up with some contrived cases where they really want to store an Optional
in a field or a collection, but in general, it is best to avoid doing this.
我敢肯定有人会想出一些人为的案例,他们真的想将 an 存储Optional
在字段或集合中,但一般来说,最好避免这样做。
回答by peter.petrov
Seems Optional
is only useful if the type T in Optional is a primitive type like int
, long
, char
, etc. For "real" classes, it does not make sense to me as you can use a null
value anyway.
似乎Optional
只有在 Optional 中的类型 T 是像int
, long
,char
等原始类型时才有用。对于“真正的”类,这对我来说没有意义,因为null
无论如何您都可以使用值。
I think it was taken from here (or from another similar language concept).
我认为它是从这里(或从另一个类似的语言概念)获取的。
In C# this Nullable<T>
was introduced long ago to wrap value types.
在 C# 中Nullable<T>
,很久以前就引入了它来包装值类型。
回答by Peter Lawrey
Personally, I prefer to use IntelliJ's Code Inspection Toolto use @NotNull
and @Nullable
checks as these are largely compile time (can have some runtime checks) This has lower overhead in terms of code readability and runtime performance. It is not as rigorous as using Optional, however this lack of rigour should be backed by decent unit tests.
就我个人而言,我更喜欢使用IntelliJ 的代码检查工具来使用@NotNull
和@Nullable
检查,因为这些主要是编译时间(可以进行一些运行时检查)这在代码可读性和运行时性能方面具有较低的开销。它不像使用 Optional 那样严格,但是这种缺乏严谨性应该得到体面的单元测试的支持。
public @Nullable Foo findFoo(@NotNull String id);
public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);
public class Book {
private List<Pages> pages;
private @Nullable Index index;
}
List<@Nullable Foo> list = ..
This works with Java 5 and no need to wrap and unwrap values. (or create wrapper objects)
这适用于 Java 5,无需包装和解包值。(或创建包装对象)
回答by Behe
I think the Guava Optional and their wiki page puts it quite well:
我认为 Guava Optional 和他们的 wiki 页面说得很好:
Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case. Null makes it disturbingly easy to simply forget things, and though FindBugs helps, we don't think it addresses the issue nearly as well.
This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves for their code to compile. -- (Source: Guava Wiki - Using and Avoiding null - What's the point?)
除了通过给 null 一个名字带来的可读性的增加之外,Optional 的最大优点是它的防白痴性。如果您希望程序完全编译,它会迫使您主动考虑不存在的情况,因为您必须主动打开 Optional 并解决该情况。Null 使得简单地忘记事情变得非常容易,虽然 FindBugs 有所帮助,但我们认为它几乎不能解决这个问题。
当您返回可能“存在”也可能不“存在”的值时,这一点尤其重要。您(和其他人)更可能忘记 other.method(a, b) 可能返回空值,而不是您在实现 other.method 时可能忘记 a 可能为空。返回 Optional 使调用者不可能忘记这种情况,因为他们必须自己解开对象才能编译他们的代码。--(来源:Guava Wiki - 使用和避免 null - 有什么意义?)
Optional
adds some overhead, but I think its clear advantage is to make it explicitthat an object might be absent and it enforces that programmers handle the situation. It prevents that someone forgets the beloved != null
check.
Optional
增加了一些开销,但我认为它的明显优势是明确表示对象可能不存在,并强制程序员处理这种情况。它可以防止有人忘记心爱的!= null
支票。
Taking the example of 2, I think it is far more explicit code to write:
以2为例,我认为编写更明确的代码:
if(soundcard.isPresent()){
System.out.println(soundcard.get());
}
than
比
if(soundcard != null){
System.out.println(soundcard);
}
For me, the Optional
better captures the fact that there is no soundcard present.
对我来说,Optional
更好地捕捉到没有声卡的事实。
My 2¢ about your points:
我的 2¢ 关于你的观点:
public Optional<Foo> findFoo(String id);
- I am not sure about this. Maybe I would return aResult<Foo>
which might be emptyor contain aFoo
. It is a similar concept, but not really anOptional
.public Foo doSomething(String id, Optional<Bar> barOptional);
- I would prefer @Nullable and a findbugs check, as in Peter Lawrey's answer- see also this discussion.- Your book example - I am not sure if I would use the Optional internally, that might depend on the complexity. For the "API" of a book, I would use an
Optional<Index> getIndex()
to explicitly indicate that the book might not have an index. - I would not use it in collections, rather not allowing null values in collections
public Optional<Foo> findFoo(String id);
- 我不确定这一点。也许我会返回一个Result<Foo>
可能为空或包含Foo
. 这是一个类似的概念,但不是真正的Optional
.public Foo doSomething(String id, Optional<Bar> barOptional);
- 我更喜欢 @Nullable 和 findbugs 检查,如Peter Lawrey 的回答- 另请参阅此讨论。- 您的书籍示例 - 我不确定是否会在内部使用 Optional,这可能取决于复杂性。对于一本书的“API”,我会使用 an
Optional<Index> getIndex()
来明确指出这本书可能没有索引。 - 我不会在集合中使用它,而不允许在集合中使用空值
In general, I would try to minimize passing around null
s. (Once burnt...)
I think it is worth to find the appropriate abstractions and indicate to the fellow programmers what a certain return value actually represents.
一般来说,我会尽量减少null
s 的传递。(一旦被烧毁......)我认为找到适当的抽象并向其他程序员表明某个返回值实际代表什么是值得的。
回答by fge
Here is an interesting usage (I believe) for... Tests.
这是一个有趣的用法(我相信)用于...测试。
I intend to heavily test one of my projects and I therefore build assertions; only there are things I have to verify and others I don't.
我打算对我的一个项目进行大量测试,因此我构建了断言;只有一些事情我必须验证,而其他事情我不需要。
I therefore build things to assert and use an assert to verify them, like this:
因此,我构建东西来断言并使用断言来验证它们,如下所示:
public final class NodeDescriptor<V>
{
private final Optional<String> label;
private final List<NodeDescriptor<V>> children;
private NodeDescriptor(final Builder<V> builder)
{
label = Optional.fromNullable(builder.label);
final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
= ImmutableList.builder();
for (final Builder<V> element: builder.children)
listBuilder.add(element.build());
children = listBuilder.build();
}
public static <E> Builder<E> newBuilder()
{
return new Builder<E>();
}
public void verify(@Nonnull final Node<V> node)
{
final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
nodeAssert.hasLabel(label);
}
public static final class Builder<V>
{
private String label;
private final List<Builder<V>> children = Lists.newArrayList();
private Builder()
{
}
public Builder<V> withLabel(@Nonnull final String label)
{
this.label = Preconditions.checkNotNull(label);
return this;
}
public Builder<V> withChildNode(@Nonnull final Builder<V> child)
{
Preconditions.checkNotNull(child);
children.add(child);
return this;
}
public NodeDescriptor<V> build()
{
return new NodeDescriptor<V>(this);
}
}
}
In the NodeAssert class, I do this:
在 NodeAssert 类中,我这样做:
public final class NodeAssert<V>
extends AbstractAssert<NodeAssert<V>, Node<V>>
{
NodeAssert(final Node<V> actual)
{
super(Preconditions.checkNotNull(actual), NodeAssert.class);
}
private NodeAssert<V> hasLabel(final String label)
{
final String thisLabel = actual.getLabel();
assertThat(thisLabel).overridingErrorMessage(
"node's label is null! I didn't expect it to be"
).isNotNull();
assertThat(thisLabel).overridingErrorMessage(
"node's label is not what was expected!\n"
+ "Expected: '%s'\nActual : '%s'\n", label, thisLabel
).isEqualTo(label);
return this;
}
NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
{
return label.isPresent() ? hasLabel(label.get()) : this;
}
}
Which means the assert really only triggers if I want to check the label!
这意味着断言只有在我想检查标签时才会触发!
回答by Nicolai
I'm late to the game but for what it's worth, I want to add my 2 Cents. They go against the design goal of Optional
, which is well summarized by Stuart Marks's answer, but I'm still convinced of their validity (obviously).
我迟到了,但就其价值而言,我想加上我的 2 美分。它们违背了 的设计目标Optional
,Stuart Marks 的回答很好地总结了这一点,但我仍然相信它们的有效性(显然)。
Use Optional Everywhere
随处使用可选
In General
一般来说
I wrote an entire blog post about using Optional
but it basically comes down to this:
我写了一篇关于使用Optional
的完整博客文章,但基本上归结为:
- design your classes to avoid optionality wherever feasibly possible
- in all remaining cases, the default should be to use
Optional
instead ofnull
- possibly make exceptions for:
- local variables
- return values and arguments to private methods
- performance critical code blocks (no guesses, use a profiler)
- 设计您的课程,以尽可能避免可选性
- 在所有剩余的情况下,默认值应该是使用
Optional
而不是null
- 可能例外:
- 局部变量
- 将值和参数返回给私有方法
- 性能关键代码块(不要猜测,使用分析器)
The first two exceptions can reduce the perceived overhead of wrapping and unwrapping references in Optional
. They are chosen such that a null can never legally pass a boundary from one instance into another.
前两个异常可以减少在Optional
. 它们的选择使得空值永远不能合法地将边界从一个实例传递到另一个实例。
Note that this will almost never allow Optional
s in collections which is almost as bad as null
s. Just don't do it. ;)
请注意,这几乎永远不会允许Optional
s 出现在几乎与null
s一样糟糕的集合中。只是不要这样做。;)
Regarding your questions
关于你的问题
- Yes.
- If overloading is no option, yes.
- If other approaches (subclassing, decorating, ...) are no option, yes.
- Please no!
- 是的。
- 如果无法选择重载,则可以。
- 如果没有其他方法(子类化、装饰等),是的。
- 请不!
Advantages
好处
Doing this reduces the presence of null
s in your code base, although it does not eradicate them. But that is not even the main point. There are other important advantages:
这样做会减少null
s 在您的代码库中的存在,尽管它不会根除它们。但这甚至不是重点。还有其他重要的优点:
Clarifies Intent
阐明意图
Using Optional
clearly expresses that the variable is, well, optional. Any reader of your code or consumer of your API will be beaten over the head with the fact that there might be nothing there and that a check is necessary before accessing the value.
UsingOptional
清楚地表示该变量是可选的。您的代码的任何读者或您的 API 的使用者都将被殴打,因为那里可能什么都没有,并且在访问该值之前需要进行检查。
Removes Uncertainty
消除不确定性
Without Optional
the meaning of a null
occurrence is unclear. It could be a legal representation of a state (see Map.get
) or an implementation error like a missing or failed initialization.
没有发生Optional
的意义null
是不清楚的。它可能是状态的合法表示(请参阅 参考资料Map.get
)或实现错误,例如初始化丢失或失败。
This changes dramatically with the persistent use of Optional
. Here, already the occurrence of null
signifies the presence of a bug. (Because if the value were allowed to be missing, an Optional
would have been used.) This makes debugging a null pointer exception much easier as the question of the meaning of this null
is already answered.
随着Optional
. 在这里,已经发生了null
意味着存在错误。(因为如果允许缺少该值,Optional
则将使用an 。)这使得调试空指针异常变得更加容易,因为 this 的含义问题null
已经得到解答。
More Null Checks
更多空检查
Now that nothing can be null
anymore, this can be enforced everywhere. Whether with annotations, assertions or plain checks, you never have to think about whether this argument or that return type can be null. It can't!
现在什么都没有null
了,这可以在任何地方强制执行。无论是注释、断言还是普通检查,您都不必考虑这个参数或那个返回类型是否可以为空。不能!
Disadvantages
缺点
Of course, there is no silver bullet...
当然,没有银弹……
Performance
表现
Wrapping values (especially primitives) into an extra instance can degrade performance. In tight loops this might become noticeable or even worse.
将值(尤其是基元)包装到额外的实例中会降低性能。在紧密的循环中,这可能会变得明显甚至更糟。
Note that the compiler might be able to circumvent the extra reference for short lived lifetimes of Optional
s. In Java 10 value typesmight further reduce or remove the penalty.
请注意,编译器可能能够绕过Optional
s短暂生命周期的额外引用。在 Java 10 中,值类型可能会进一步减少或消除惩罚。
Serialization
序列化
Optional
is not serializablebut a workaroundis not overly complicated.
Optional
不可序列化,但解决方法并不过分复杂。
Invariance
不变性
Due to the invariance of generic types in Java, certain operations become cumbersome when the actual value type is pushed into a generic type argument. An example is given here (see "Parametric polymorphism").
由于 Java 中泛型类型的不变性,当实际值类型被推入泛型类型参数时,某些操作会变得很麻烦。此处给出了一个示例(请参阅“参数多态性”)。
回答by Kumar Abhishek
Java SE 8 introduces a new class called java.util.Optional,
Java SE 8 引入了一个名为 java.util.Optional 的新类,
You can create an empty Optional or Optional with null value.
您可以创建一个空的 Optional 或带有 null 值的 Optional。
Optional<String> emptyOptional = Optional.empty();
And here is an Optional with a non-null value:
这是一个具有非空值的 Optional :
String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );
Do Something If a Value Is Present
如果存在值,则做某事
Now that you have an Optional object, you can access the methods available to explicitly deal with the presence or absence of values. Instead of having to remember to do a null check, as follows:
现在您有了一个 Optional 对象,您可以访问可用于显式处理值存在与否的方法。不必记住进行空检查,如下所示:
String nullString = null;
if (nullString != null) {
System.out.println(nullString);
}
You can use the ifPresent() method, as follows:
您可以使用 ifPresent() 方法,如下所示:
Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);
package optinalTest;
import java.util.Optional;
public class OptionalTest {
public Optional<String> getOptionalNullString() {
return null;
// return Optional.of("TESt");
}
public static void main(String[] args) {
OptionalTest optionalTest = new OptionalTest();
Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());
if (optionalNullString.isPresent()) {
System.out.println(optionalNullString.get());
}
}
}
回答by ctomek
From Oracle tutorial:
来自Oracle 教程:
The purpose of Optional is not to replace every single null reference in your codebase but rather to help design better APIs in which—just by reading the signature of a method—users can tell whether to expect an optional value. In addition, Optional forces you to actively unwrap an Optional to deal with the absence of a value; as a result, you protect your code against unintended null pointer exceptions.
Optional 的目的不是替换代码库中的每一个空引用,而是帮助设计更好的 API,其中——只需读取方法的签名——用户就可以判断是否需要一个可选值。此外,Optional 强制您主动打开 Optional 以处理缺少值的情况;因此,您可以保护您的代码免受意外空指针异常的影响。
回答by oopexpert
I do not think that Optional is a general substitute for methods that potentially return null values.
我不认为 Optional 是可能返回空值的方法的通用替代品。
The basic idea is: The absence of a value does not mean that it potentially is available in the future. It's a difference between findById(-1) and findById(67).
基本思想是:值的缺失并不意味着它可能在未来可用。这是 findById(-1) 和 findById(67) 之间的区别。
The main information of Optionals for the caller is that he may not count on the value given but it may be available at some time. Maybe it will disappear again and comes back later one more time. It's like an on/off switch. You have the "option" to switch the light on or off. But you have no option if you do not have a light to switch on.
Optionals 给调用者的主要信息是他可能不依赖给定的值,但它可能在某个时间可用。也许它会再次消失,然后再回来一次。它就像一个开/关开关。您可以选择打开或关闭灯。但是,如果您没有可以打开的灯,则您别无选择。
So I find it too messy to introduce Optionals everywhere where previously null was potentially returned. I will still use null, but only in restricted areas like the root of a tree, lazy initialization and explicit find-methods.
所以我发现在以前可能返回 null 的任何地方引入 Optionals 太麻烦了。我仍将使用 null,但仅限于受限区域,例如树的根、延迟初始化和显式查找方法。
回答by artifex
1 - As a public method return type when the method could return null:
1 - 当方法可以返回 null 时,作为公共方法返回类型:
Here is a good articlethat shows usefulness of usecase #1. There this code
这是一篇很好的文章,展示了用例 #1 的有用性。有这个代码
...
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
isocode = isocode.toUpperCase();
}
}
}
...
is transformed to this
变成了这个
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.map(Country::getIsocode)
.orElse("default");
by using Optional as a return value of respective gettermethods.
通过使用 Optional 作为各个getter方法的返回值。