【问题标题】:Java 8 Optional asSet()Java 8 可选的 asSet()
【发布时间】:2014-08-09 13:53:30
【问题描述】:

所以我已经使用 Guava 的 Optional 有一段时间了,我正在迁移到 Java 8,所以我想使用它的 Optional 类,但它没有我最喜欢的 Guava 方法:@987654324 @。有没有办法使用我没有看到的 Java 8 Optional 来做到这一点。我喜欢能够将Optional 视为一个集合,所以我可以这样做:

for (final User u : getUserOptional().asSet()) {
   return u.isPermitted(getPermissionRequired());
}

在某些情况下避免需要额外的变量。

例如:

 Optional<User> optUser = getUserOptional();
 if (optUser.isPresent()) {
     return optUser.get().isPermitted(getPermissionRequired());
 }

有没有一种简单的方法可以在 Java 8 的 Optional 中复制 Guava 风格?

谢谢

【问题讨论】:

标签: java guava java-8 optional


【解决方案1】:

有一种将Optional 转换为Set 的简单方法。它就像Optional 的任何其他转换一样工作:

给定一个Optional&lt;T&gt; o,您可以调用

o.map(Collections::singleton).orElse(Collections.emptySet())

获取Set&lt;T&gt;。如果你不喜欢 Collections.emptySet() 在任何情况下都被调用的想法,你可以把它变成一个惰性求值:

o.map(Collections::singleton).orElseGet(Collections::emptySet)

但是,该方法过于简单,无法产生性能差异。所以这只是编码风格的问题。

您也可以使用它来按预期进行迭代:

for(T t: o.map(Collections::singleton).orElse(Collections.emptySet()))
    // do something with t, may include a return statement

【讨论】:

  • 太棒了,这就是我要找的!
  • @csyperski 我不明白你为什么要坚持使用你在 Guava 中使用的这个空的 Set + for 循环技巧,当你可以简单地执行所需的操作时(当前在loop) 在可选项上,如果可选项为空,则具有默认值 - return optUser.map(u -&gt; u.isPermitted(getPermissionRequired())).orElse(Boolean.FALSE)
  • 因为在这种情况下它有效,但并非总是如此。假设我们有以下内容: public Optional attemptLogin(String email, .... ) { // 首先让我们看看用户是否因 ( final FailedLogin failedLogin : getFailedLogin(email, ipAddress).map(Collections: :singleton).orElseGet(Collections::emptySet) ) { logger.warn("账号当前被封禁{}", failedLogin);返回 Optional.empty(); } // 执行其他登录验证 }.这可能不是最好的例子,但它是我刚刚在一些遗留代码中看到的。
  • @Eran:如果返回某个固定值是一种替代方案,您的解决方案将有效。但是,如果不返回但希望继续执行下一条语句,则不会。尽管如此,还是建议考虑重新设计没有此要求。
【解决方案2】:

您似乎只使用asSet,因此您可以编写一个 for 循环,但在 Java 8 中这是不必要的。而不是您的代码

Optional<User> optUser = getUserOptional();
if ( optUser.isPresent() ) {
    return optUser.get().isPermitted(getPermissionRequired());
}

你可以写

getUserPresent().map(optUser -> optUser.isPermitted(getPermissionRequired()))
   .orElse(false);

...或者,在许多情况下,您可以使用Optional.ifPresent(Consumer&lt;T&gt;)

【讨论】:

    【解决方案3】:

    你可以使用map

    return optUser.map(u -> u.isPermitted(getPermissionRequired()));
    

    但它会返回一个Optional&lt;WhateverTypeIsPermittedReturns&gt;

    Reference

    public Optional map(函数映射器)

    如果存在值,则对其应用提供的映射函数,然后 如果结果为非空,则返回一个描述结果的 Optional。 否则返回一个空的 Optional。

    【讨论】:

    • 所以在这种情况下我想我可以这样做: return optUser.map(u -> u.isPermitted(getPermissionRequired())).get();它会产生效果。
    • @csyperski get() 如果可选项没有值,则抛出异常,所以我认为这不是你想要的。
    • @csyperski 如果您希望 null 以防不存在值,请使用 .orElse(null)
    • 但在这种情况下它会返回一个布尔值,所以调用 get 可以安全地解开布尔值,对吧?
    • @csyperski 我认为如果isPermitted 返回布尔值,map 操作将返回 Optional,因此如果它为空(即如果原始 Optional 为空的)。这就是您应该使用 .orElse 并提供默认值的原因(例如:.orElse(Boolean.FALSE))。
    【解决方案4】:

    我也没有看到真正优雅的内置方式来做到这一点,但想提出一个类似于 Dici 的解决方案:

    public static <T> Set<T> asSet(Optional<T> opt) {
        return opt.isPresent() ?
            Collections.singletonSet(opt.get()) :
            Collections.emptySet();
    }
    

    这避免了创建新的HashSet 实例和插入可选对象。 (注意:这基本上是 Guavas PresentAbsent 类所做的“内联”版本:Present 类返回 singletonSetAbsent 类返回 emptySet)。

    用法与您的原始模式相似:

    for( final User u : asSet(getUserOptional()) ) {
       return u.isPermitted(getPermissionRequired());
    }
    

    【讨论】:

      【解决方案5】:

      您可以修改您的 getUserOptional 使其返回 Set 或实现您自己的 asSet 方法:

      public Set<User> getUserOptional() {
           Optional<User> optUser;
           //your code
           Set<User> result = new HashSet<>();
           if (optUser.isPresent())
               result.add(optUser.get());
           return result;
      }
      

      public static <T> Set<T> asSet(Optional<T> opt) {
          Set<T> result = new HashSet<>();
          if (opt.isPresent())
              result.add(opt.get());
          return result;
      }
      

      我不知道是否有内置的方法可以做到这一点。

      【讨论】:

      • 这就是我所害怕的,只是在我看来它没有那么优雅。对我来说,将 Optionals 视为零个或一个项目的集合,然后按此方式处理它们是有意义的。
      【解决方案6】:

      另一种选择是:

      getUserOptional().stream().collect(Collectors.toSet())
      

      我不相信这会更好,只是想在此处添加以确保完整性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-27
        • 1970-01-01
        • 1970-01-01
        • 2017-05-01
        • 2020-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多