Wil*_*ill 242 java optional java-8
现在已经使用Java 8超过6个月左右,我对新的API更改感到非常满意.我仍然不自信的一个领域是什么时候使用Optional.我似乎想要在任何可能的null地方使用它,而且无处可去.
似乎有很多情况我可以使用它,我不知道它是否增加了好处(可读性/无效安全性)或只是导致额外的开销.
所以,我有一些例子,我对社区是否Optional有益的想法感兴趣.
1 - 当方法可以返回时作为公共方法返回类型null:
public Optional<Foo> findFoo(String id);
Run Code Online (Sandbox Code Playgroud)
2 - 当参数可能是null以下时作为方法参数:
public Foo doSomething(String id, Optional<Bar> barOptional);
Run Code Online (Sandbox Code Playgroud)
3 - 作为bean的可选成员:
public class Book {
private List<Pages> pages;
private Optional<Index> index;
}
Run Code Online (Sandbox Code Playgroud)
4 - 在Collections:
一般来说,我不认为:
List<Optional<Foo>>
Run Code Online (Sandbox Code Playgroud)
添加任何东西 - 特别是因为可以使用filter()删除null值等,但是Optional在集合中是否有任何好的用途?
我错过了什么案例?
Stu*_*rks 189
重点Optional是为函数提供一种返回值的方法,以指示缺少返回值.见这个讨论.这允许调用者继续一系列流畅的方法调用.
这与OP的问题中的用例#1最匹配.虽然缺少值是比null更精确的公式,因为类似的东西IntStream.findFirst永远不会返回null.
对于用例#2,将可选参数传递给方法,可以使其工作,但它相当笨拙.假设您有一个方法,它接受一个字符串后跟一个可选的第二个字符串.接受一个Optional作为第二个arg将导致这样的代码:
foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());
Run Code Online (Sandbox Code Playgroud)
即使接受null也更好:
foo("bar", "baz");
foo("bar", null);
Run Code Online (Sandbox Code Playgroud)
可能最好的方法是使用一个重载方法接受单个字符串参数并为第二个提供默认值:
foo("bar", "baz");
foo("bar");
Run Code Online (Sandbox Code Playgroud)
这确实有局限性,但它比上述任何一个都要好得多.
用例#3和#4具有Optional类字段或数据结构,被认为是对API的滥用.首先,它违背Optional了顶部所述的主要设计目标.其次,它没有增加任何价值.
有三种方法可以处理缺少值Optional:提供替换值,调用函数以提供替换值,或抛出异常.如果要存储到字段中,则需要在初始化或分配时执行此操作.如果您正在将值添加到列表中,正如OP所提到的那样,您还可以选择不添加值,从而"消除"缺少的值.
我敢肯定有人可能会想出一些他们真正想要存放Optional在一个领域或一个集合中的人工案例,但总的来说,最好避免这样做.
Nic*_*lai 69
我迟到了,但是为了它的价值,我想加上我的2分.他们违背了设计目标Optional,斯图尔特马克斯的回答很好地总结了这一点,但我仍然相信它们的有效性(显然).
我写了一篇关于使用Optional的完整博文,但它基本上归结为:
Optional而不是null前两个例外可以减少包装和展开引用的感知开销Optional.选择它们使得null永远不会合法地将边界从一个实例传递到另一个实例.
请注意,这几乎不会允许Optional集合中的s几乎与nulls 一样糟糕.只是不要这样做.;)
这样做可以减少null代码库中s 的存在,尽管它不能消除它们.但这甚至不是主要观点.还有其他重要的优点:
使用Optional清楚地表明变量是可选的.您的代码的任何读者或您的API的消费者都将遭受殴打,因为在访问该值之前可能没有任何内容并且需要进行检查.
没有发生Optional的意义null尚不清楚.它可能是状态的合法表示(请参阅参考资料Map.get)或实现错误,例如缺少或失败的初始化.
随着持续使用,这会发生巨大变化Optional.在这里,已经发生的事件null表明存在错误.(因为如果允许丢失该值,Optional则会使用.)这使得调试空指针异常变得更加容易,因为null已经回答了这个问题的含义问题.
现在已经没有任何东西null了,这可以在任何地方强制执行.无论是注释,断言还是普通检查,您都不必考虑此参数或返回类型是否为null.它不能!
当然,没有银弹......
将值(尤其是基元)包装到额外的实例中会降低性能.在紧密的循环中,这可能会变得明显甚至更糟.
请注意,编译器可能能够规避Optionals的短寿命的额外引用.在Java 10中,值类型可能会进一步减少或消除惩罚.
Optional不可序列化,但解决方法并不过分复杂.
由于Java中泛型类型的不变性,当将实际值类型推入泛型类型参数时,某些操作会变得很麻烦.这里给出一个例子(参见"Parametric polymorphism").
Pet*_*rey 26
就个人而言,我更喜欢使用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 = ..
Run Code Online (Sandbox Code Playgroud)
这适用于Java 5,无需包装和解包值.(或创建包装器对象)
Beh*_*ehe 24
我认为Guava Optional和他们的wiki页面非常适合:
除了通过赋予null名称而增加可读性之外,Optional的最大优点是它的白痴证明.如果您希望程序完全编译,它会强制您主动考虑缺席情况,因为您必须主动解包可选并解决该情况.Null使得简单地忘记事情变得非常容易,尽管FindBugs有所帮助,但我们认为它几乎不会解决这个问题.
当您返回可能存在或可能不存在的值时,这尤其重要.你(和其他人)更有可能忘记other.method(a,b)可以返回一个空值而不是你可能会忘记当你实现other.method时a可能为null.返回Optional使得调用者无法忘记这种情况,因为他们必须自己解包对象以便编译代码.- (来源:Guava Wiki - 使用和避免null - 重点是什么?)
Optional增加了一些开销,但我认为它的明显优势是明确
表示某个对象可能不存在并强制程序员处理这种情况.它可以防止有人忘记心爱的!= null支票.
以2为例,我认为编写代码要明确得多:
if(soundcard.isPresent()){
System.out.println(soundcard.get());
}
Run Code Online (Sandbox Code Playgroud)
比
if(soundcard != null){
System.out.println(soundcard);
}
Run Code Online (Sandbox Code Playgroud)
对我来说,Optional更好地捕捉到没有声卡存在的事实.
关于你的观点我的2¢:
public Optional<Foo> findFoo(String id); - 我不确定这个.也许我会返回一个Result<Foo>可能是空的或包含一个Foo.这是一个类似的概念,但不是真的Optional.public Foo doSomething(String id, Optional<Bar> barOptional);- 我更喜欢@Nullable和一个findbugs检查,就像Peter Lawrey的回答一样 - 也参见这个讨论.Optional<Index> getIndex()明确表示该书可能没有索引.一般来说,我会尽量减少绕过nulls.(一旦被烧掉......)我认为找到合适的抽象是值得的,并向其他程序员表明某个返回值实际代表什么.
在 Java 中,除非您沉迷于函数式编程,否则不要使用它们。
它们没有作为方法参数的地方(我保证有一天有人会给你一个空的可选,而不仅仅是一个空的可选)。
它们对返回值有意义,但它们会邀请客户端类继续拉伸行为构建链。
FP 和链在像 java 这样的命令式语言中几乎没有地位,因为它很难调试,而不仅仅是阅读。当你走到线下时,你无法知道程序的状态和意图;你必须深入了解它(进入通常不是你的代码和许多堆栈帧深,尽管步骤过滤器)并且你必须添加大量断点以确保它可以停止在你添加的代码/lambda中,而不是简单地走 if/else/call 琐碎的行。
如果您想要函数式编程,请选择 java 以外的其他东西,并希望您拥有调试它的工具。
1-当方法可以返回null时,作为公共方法的返回类型:
这是一篇很好的文章,展示了用例#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();
}
}
}
...
Run Code Online (Sandbox Code Playgroud)
变成了这个
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.map(Country::getIsocode)
.orElse("default");
Run Code Online (Sandbox Code Playgroud)
通过使用Optional作为各个getter方法的返回值。
| 归档时间: |
|
| 查看次数: |
75567 次 |
| 最近记录: |