Java 8中Optional类型的有效用法

这是Java 8中Optional类型的有效(预期)用法吗?

class Foo { private final Integer id; private final String name; private final String countryCode; Foo(final Integer id, final String name, final String countryCode) { this.id = id; this.name = name; this. countryCode = countryCode; } public String getName() { return name; } public String getCountryCode() { return countryCode; } } class FooSrv { private Optional getFoo(final Integer id) { return id != null && id == 1 ? Optional.of(new Foo(id, "Bar", "US")) : Optional.empty(); } private boolean isFooValid(final Integer id) { return getFoo(id) .filter(f -> "Bar".equals(f.getName()) && "US".equals(f.getCountryCode())) .map(f -> true) .orElse(false); } } 

我会再接下来。

这是有效的用法吗? 是的,从狭义上讲它会编译并产生您期望的结果。

这是用途吗? 不,现在,有时事情发现它们的用处超出了原来的范围,如果这样做有效,那就太好了。 但是对于Optional ,我们发现通常情况不会很好。

Brian Goetz和我讨论了JavaOne 2015演讲中的Optional一些问题, 使用Java 8 Lambdas和Streams进行API设计

  • 链接到video
  • 链接到幻灯片

Optional的主要用途如下:(幻灯片36)

可选的目的是为库方法返回类型提供有限的机制,其中明确需要表示“无结果”,并且使用null的情况极有可能导致错误

Optional链接方法的能力无疑是非常酷的,并且在某些情况下它减少了条件逻辑的混乱。 但通常情况下这并没有成功。 一个典型的代码气味是,代替使用方法链接来处理从某个方法返回的Optional的代码,它从可以为空的东西创建一个Optional ,以便链接方法并避免条件。 这是一个实际的例子(也来自我们的演示文稿,幻灯片42):

 // BAD String process(String s) { return Optional.ofNullable(s).orElseGet(this::getDefault); } // GOOD String process(String s) { return (s != null) ? s : getDefault(); } 

使用Optional的方法更长,大多数人发现它比传统代码更模糊。 不仅如此,它还没有充分的理由造成额外的垃圾。

底线:仅仅因为你可以做某事并不意味着你应该这样做。

由于这或多或少是一个基于意见的问题,我会抛弃我的。如果你想说的话

 if (id == 1) { Foo f = new Foo(id, "Bar", "US"); return "Bar".equals(f.getName()) && "US".equals(f.getCountryCode()); } else { return false; } 

然后就这么说吧。 使事物“有效”不会自动使事情更清晰或更好。 通过引入一个不必要的Optional ,一对lambdas,以及一些我必须查找的Optional方法,您已经使代码更复杂且难以理解。 我不认为Java的设计者“有意”让人们使用Optional来帮助使代码更加模糊。

编辑:在阅读了一些回复后,我认为值得添加一些评论。 这不是我熟悉的函数式编程习惯,这将使其更难理解。 我熟悉的习语主要涉及Java流,或(在其他语言中)应用于数组或列表中的多个值或多个值的其他集合的function习语。 在这些情况下,一旦你超越了陌生程度,function语法就可以看作是一种改进,因为它允许隐藏一些细节(循环索引,迭代器,运行指针,累加器变量)。 总的来说,它可以简化事情。 这个例子本身并没有做任何这样的简化。

但是,某些Optionalfunction在流上下文中很有用。 假设我们有一个parseInt()方法,它返回一个Optional ,如果输入字符串无效,则为空。 (Java 8确实应该提供这个。)这样可以很容易地获取一个字符串数组并生成一个整数数组,其中不解析的字符串只是从结果中删除 – 在流map()使用parseInt map() ,并使用流filter过滤掉空的Optional s。 (我已经看到多个StackOverflow问题,询问如何执行此操作。)如果您只想保留正值,可以使用Optional.empty()在使用流filter之前将nonposit更改为Optional.empty() (虽然在这种情况下,您可以在之后添加另一个流filter,但在更复杂的情况下, Optionalfilter可能更有用)。 从function的角度来看,这就是我认为Optional的主要优点。 它允许您一次处理一组值,方法是为您提供一种表示“非值”的方法,并编写一个仍然可以使用它们的函数。 所以我想除了替换null之外, Optional的主要用途是在整个序列中应用函数时表示值序列中的空格。

询问它是否“有效”是基于意见的,但是它是否是预期的用例:不,它不是。

Oracle的Java语言架构师Brian Goetz表示,Optional的用例适用于需要“无值”标记的情况, 并且当使用null ,可能会导致错误 。 具体来说,如果您的方法的合理用户不太可能考虑其结果为null的可能性,那么您应该使用Optional。 它显然不是一般的“可能”类型的对象,因为你在这里使用它。

在您的情况下,返回Optional的方法是private。 这意味着它只能由类的实现者使用,并且您可以假设他们对类的方法有很好的了解 – 包括哪些方法可能返回null 。 由于没有合理的混淆风险,Brian Goetz(可能)会说他不会认为这是一个有效的用例。

它有点人为,但“有效”(如’语法’),但正如@yshavit指出的那样,它旨在用于图书馆开发。


之前的答案是由于FP代码难以阅读。 下面是评论(有点详细,b / c是javadoc评论)但仍然。 更容易阅读恕我直言。 (第二是没有评论,至少是对齐以帮助提高可读性)

 private boolean isFooValid(final Integer id) { return getFoo(id) // filter if 'f' matches the predicate, return Optional w/f if true, empty Optional if false .filter(f -> "Bar".equals(f.getName()) && "US".equals(f.getCountryCode())) // If a value is present, apply the provided mapping function to it, // If non-null, return an Optional describing the result. .map(f -> true) // Return the value if present, otherwise return other. .orElse(false); } 

或者至少排队,以便更明显地发生什么,更容易阅读。

 private boolean isFooValid(final Integer id) { return getFoo(id) .filter(f -> "Bar".equals(f.getName()) && "US".equals(f.getCountryCode())) .map(f -> true) .orElse(false); }