【问题标题】:My method returning an Optional cannot be used in a functional-like way我的返回 Optional 的方法不能以类似功能的方式使用
【发布时间】:2016-10-24 09:45:36
【问题描述】:

我正在编写一个方法,旨在递归地搜索嵌套集合中的值并返回包含该值的集合:

@SuppressWarnings("unchecked")
public static <E,
               R extends Collection<? extends E>> Optional<R> findRecursively(Collection<?> collection, E element)
                  throws ClassCastException {
   if (collection.isEmpty())
      return Optional.ofNullable(null);

   boolean nested = collection.stream()
                              .allMatch(e -> isSubclass(e.getClass(), Collection.class));
   for (Object c : collection) {
      R result;

      if (nested) {
         Optional<R> recursiveResult = findRecursively((Collection<?>) c, element);
         result = recursiveResult.orElse(null);
      } else {
         result = c.equals(element) ? (R) collection : null;
      }

      if (result != null)
         return Optional.of(result);
   }
   return Optional.ofNullable(null);
}

这很好用,但是当我使用该方法时,如果不先将其提供给变量,我就无法直接使用返回的 Optional:

Collection<String> collection = null;
Set<String> set = Util.findRecursively(collection, "")
                      .orElseThrow(RuntimeException::new);

在这种情况下,编译器无法知道方法的返回类型。 我不知道有什么好的可能性让它发挥作用。

我想出了另外两种方法,也不是很好:

  1. 我添加了一个返回类型应该返回的参数,如:

    public static <E,
                   R extends Collection<E>> Optional<R> findRecursively(Collection<?> collection,
                                                                        E element,
                                                                        Class<R> returnType) {...
    

    但我不喜欢这样,因为附加参数(实际上)是不必要的,并且使方法不太容易理解。

  2. 我只返回集合对象,而不是 Optional。但在那种情况下,我不能直接创建一个 Optional 并像这样调用它:

    Collection<String> collection = null;
    Set<String> set = Optional.ofNullable(Util.findRecursively(collection, ""))
                              .orElseThrow(RuntimeException::new);
    

    因为这里编译器不知道返回类型,也无法推断of() 方法的类型参数。

有人知道这个问题的好解决方案吗?或者建议在这里走哪条路?

【问题讨论】:

  • 返回集合的 Optional 很大程度上是对 Optional 的滥用(see alsothat as well)。只需返回一个空集合。然后在调用站点为空时抛出一些异常。
  • 我认为您的问题归结为未经检查的演员表。您基本上是在告诉:“我将返回您请求的任何集合实现”,然后您不检查请求的内容并盲目地转换它。因此,我们过去有similar or even worse issues。带有returnType 参数的解决方案是最好的解决方案,您甚至可以使用returnType.cast(collection) 来避免未经检查的强制转换。
  • 好吧,Class 对象的cast 方法不是未经检查的强制转换,换句话说,正如该术语的字面意思告诉你的那样,@987654333 @ 实际上会检查对象是否真的是类的实例。
  • 除此之外,整个方法都被破坏了。仅仅因为集合包含E 类型的元素并不能证明它是Collection&lt;E&gt;,例如Set&lt;Number&gt; 可以包含 Integer 类型的实例,但这并不意味着它是 Set&lt;Integer&gt;。更糟糕的是,调用者可以替换任何集合类型,例如让它返回一个List,即使输入是Set,也不会收到任何警告。您的示例已经通过传入一个参数来证明这一点,其类型为Collection,但希望神奇地得到一个Set,而没有任何证据证明源曾经是Set
  • 可能存在一个更通用的设计问题,即使用通用集合而不是定义自己的类来表示您的数据结构——在后台使用集合,但这会被隐藏,并且您不会有嵌套集合.

标签: java generics java-8 optional


【解决方案1】:

您可以在同一行中声明具体类型而不声明 var:

Util.<Collection, String, Set<String>>findRecursively(collection, "")...

【讨论】:

  • 这正是我想要的,谢谢。 :)
猜你喜欢
  • 1970-01-01
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-14
  • 2016-05-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多