【问题标题】:Cast from Optional<> to ArrayList<>从 Optional<> 转换为 ArrayList<>
【发布时间】:2015-10-19 17:19:16
【问题描述】:

我有以下情况:

public ArrayList<A> getMethods(){
    return b.c.test();
}

所以,我的问题是b.c.test() 返回一个以Optional&lt;A&gt; 作为返回类型的值。但我需要返回一个ArrayList&lt;A&gt;

所以,我尝试将其转换为:

public ArrayList<A> getMethods(){
    return (ArrayList<A>)b.c.test();
}

但是 Eclipse 说从Optional&lt;A&gt;ArrayList&lt;A&gt; 的这种转换是不可能的。

我该如何解决这个问题?

【问题讨论】:

  • 嗯,是的,Optional 不是ArrayList,它们当然不能被强制转换。你是什​​么意思你“不能改变它”?什么是“它”,为什么不能改变?
  • Optianal&lt;A&gt; 是什么?
  • 它不是一个集合,你所说的“转换”到 ArrayList 是什么意思?
  • @ShadowRay "什么是Optianal&lt;A&gt;?"如果您的问题很笼统,那么:从 Guava 添加到 Java 8 是非常好的事情。它帮助我们避免空值 code.google.com/p/guava-libraries/wiki/…

标签: java arraylist casting optional


【解决方案1】:

我假设您的预期语义是“如果存在该值,则返回一个包含单个项目的列表,否则返回一个空列表。”在这种情况下,我会建议如下:

ArrayList<A> result = new ArrayList<>();
b.c.test().ifPresent(result::add);
return result;

但是,我建议您的返回类型应为 List&lt;A&gt; 而不是 ArrayList&lt;A&gt;,因为这样您就有机会在不更改调用者的情况下更改列表的类型。如果可选值不存在,它还允许您返回Collections.EMPTY_LIST,这比创建不必要的ArrayList 更有效。

更新:Java 9 现在有了更简单的选择:

b.c.test().stream().collect(Collectors.toList());

更新:Java 16 甚至更简单的选择:

b.c.test().stream().toList();

【讨论】:

    【解决方案2】:

    在这种情况下,完全可以不使用流:

    public static <T> List<T> toList(Optional<T> opt) {
        return opt.isPresent()
                ? Collections.singletonList(opt.get())
                : Collections.emptyList();
    }
    

    或者,使用函数式 API 的相同代码:

    public static <T> List<T> toList(Optional<T> opt) {
        return opt
                .map(Collections::singletonList)
                .orElseGet(Collections::emptyList);
    }
    

    我更喜欢上面的变体,因为我确信它不会在 Java 堆上创建任何不必要的对象。

    【讨论】:

      【解决方案3】:

      如果每个人都坚持使用流来解决这个问题,那应该比使用ifPresent()更地道 不幸的是,Java 8 没有Optional.stream() 方法,所以无法做到:

       optional.stream().collect(Collectors.toList());
      

      另请参阅:Using Java 8's Optional with Stream::flatMap

      但在 JDK 9 中,它将被添加(并且该代码实际上已经在 J​​ava 9 上运行)

      Optional<Integer> o = Optional.empty();
      final List<Integer> list = o.stream().collect(Collectors.toList());
      System.out.println(list);
      

      【讨论】:

        【解决方案4】:
        return b.c.test()
            .map(Arrays::asList).map(ArrayList::new)
            .orElseGet(ArrayList::new);
        

        如果可选项有一个值,它会将其“映射”到带有Arrays.asListList&lt;A&gt;,然后通过new ArrayList&lt;A&gt;(List&lt;A&gt;) 构造函数映射到ArrayList;否则它会通过空的构造函数产生一个空的ArrayList

        这可以更明确地写成:

        return b.c.test()
            .map(value -> new ArrayList<A>(Arrays.asList(value)))
            .orElseGet(() -> new ArrayList<A>());
        

        【讨论】:

        • 这似乎过于冗长了;这实际上是在滥用 Java 8 的函数式习语来完成一项非常简单的任务吗?
        • 我不知道,我喜欢这种风格。我喜欢缺少临时变量。我认为复杂性是过于具体的返回类型的结果。如果是List 而不是ArrayList,则可以更直接地写成:map(Collections::singletonList).orElseGet(Collections::emptyList)。我喜欢它的外观。
        • IMO,@sprinter 答案中的临时变量使代码更具可读性(也更简洁)。 maporElseGet 很有用——在正确的地方使用时。你的解决方案让我想起了Guava's Functionals Explained 中提出的警告——命令式代码应该是默认的,即使在 Java 8 中也是如此。
        【解决方案5】:

        使用 Java9,您可以使用新添加的 Optional::stream API 来做到这一点:

        Optional<List<A>> list;
        List<A> collect = list.stream()
                       .flatMap(Optional::stream)
                       .collect(Collectors.toList());
        

        【讨论】:

          【解决方案6】:

          如果你使用 Guava 的Optional,你可以这样做:

          return new ArrayList<>(b.c.test().asSet());
          

          这将从Optional(如果存在)中提取值并将其添加到新的ArrayList

          如果您使用的是 Java 8,@sprinter 的答案就是您所需要的。

          【讨论】:

            【解决方案7】:

            Optional 是一个容器对象,它可能包含也可能不包含非空值。

            在 ArrayList 术语中,我会将其翻译为具有 0 或 1 个成员的数组。

            public ArrayList<A> getMethods(){
              Optional<A> opt = b.c.test();
              ArrayList<A> res = new ArrayList<>();
              if ( opt.isPresent() )
                res.add( opt.get() );
              return res;
            }
            

            【讨论】:

            • Optional.empty() 是一个静态方法,它返回一个新的空Optional。你想要Optional.isPresent()。还有更简洁的方法可以做到这一点(@sprinter 的回答)。
            • @JoseAntonioDuraOlmos 我认为您的意思是if (opt.isPresent()) 而不是if (!opt.isPresent())。目前,当您尝试 get 并清空可选时,这将引发异常。
            • 当然,盲目地将 !opt.empty() 更改为 !opt.isPresent() 会发生这种情况。
            【解决方案8】:

            从 Java 9 开始

            return b.c.test().stream()
                             .collect(toList());
            

            导入静态 java.util.stream.Collectors.toList;

            从 Java 8 开始

            return b.c.test()
                       .map(List::of)
                       .orElse(emptyList());
            

            导入静态 java.util.Collections.emptyList;

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-09-04
              • 2021-06-05
              • 1970-01-01
              • 1970-01-01
              • 2015-08-06
              • 2021-02-06
              • 1970-01-01
              相关资源
              最近更新 更多