【问题标题】:Why didn't Stream have a toList() method?为什么 Stream 没有 toList() 方法?
【发布时间】:2015-05-01 04:10:49
【问题描述】:

使用 Java 8 流时,获取列表、从中创建流、处理业务并将其转换回来是很常见的。比如:

 Stream.of(-2,1,2,-5)
        .filter(n -> n > 0)
        .map(n -> n * n)
        .collect(Collectors.toList());

为什么“.collect(Collectors.toList())”部分没有快捷/方便的方法?在 Stream 接口上,有一种方法可以将结果转换为数组,称为toArray(),为什么缺少toList()

恕我直言,将结果转换为列表比转换为数组更常见。我可以忍受,但称它为丑陋是很烦人的。

有什么想法吗?

【问题讨论】:

  • 我会问相反的问题:为什么toArray() 而不是collect(toArray())。 API 爆炸是 JDK 倾向于尽可能避免的事情。我希望toArray() 有充分的理由。
  • 为什么要停在toList?让我们也添加toStacktoSettoMap
  • 通过静态导入,您可以将其缩减为 collect(toList())
  • @MarkoTopolnik 您对滑坡的观察确实是做出决定的因素。数组特别的原因是:它们特别的。 1)它们被内置到语言中(因此有更多的要求包含在内),2)排除它们会放弃一些大的并行机会(我们的 toArray 实现利用了像 SUBSIZED 这样的特性;在最好的情况下,toArray 分配一个大数组并将元素同时写入到位,零复制或锁定。)

标签: java list java-8 java-stream


【解决方案1】:

最近我编写了一个名为StreamEx 的小型库,它扩展了 Java 流并提供了这种精确的方法以及许多其他功能:

StreamEx.of(-2,1,2,-5)
    .filter(n -> n > 0)
    .map(n -> n * n)
    .toList();

这里还有toSet()、toCollection(Supplier)、joining()、groupingBy()等快捷方式。

【讨论】:

    【解决方案2】:

    Java 16 引入Stream.toList()

    Stream.of(-2,1,2,-5)
        .filter(n -> n > 0)
        .map(n -> n * n)
        .toList();
    

    新方法与现有的collect(toList()) 略有不同:它返回一个不可修改的列表。

    【讨论】:

      【解决方案3】:

      至于“为什么”,相信在cmets中有不少争论。但是,我同意你的看法,因为没有 toList() 方法很烦人。 toIterable() 方法也是如此。

      所以我将向您展示一个技巧,让您无论如何都可以使用这两种方法。幸运的是,Java 非常灵活,可以让您做各种有趣的事情。大约 10 年前,我读过 this article,它描述了一个将方法“插入”到任何给定接口的机智技巧。诀窍在于使用代理来调整没有您想要的方法的接口。多年来,我发现它具有适配器模式的所有优点,而缺乏所有缺点。这就是我所说的大事。

      这是一个示例代码,只是为了展示这个想法:

      public class Streams {
      
          public interface EnhancedStream<T>
              extends Stream<T> {
      
              List<T> toList();
      
              Iterable<T> toIterable();
          }
      
          @SuppressWarnings("unchecked")
          public static <T> EnhancedStream<T> enhance(Stream<T> stream) {
      
              return (EnhancedStream<T>) Proxy.newProxyInstance(
                  EnhancedStream.class.getClassLoader(),
                  new Class<?>[] {EnhancedStream.class}, 
                  (proxy, method, args) -> {
      
                  if ("toList".equals(method.getName())) {
      
                      return stream.collect(Collectors.toList());
      
                  } else if ("toIterable".equals(method.getName())) {
      
                      return (Iterable<T>) stream::iterator;
      
                  } else {
                      // invoke method on the actual stream
                      return method.invoke(stream, args);
                  }
              });
          }
      
          public static void main(String[] args) {
      
              Stream<Integer> stream1 = Stream.of(-2, 1, 2, -5).
                  filter(n -> n > 0).map(n -> n * n);
              List<Integer> list = Streams.enhance(stream1).toList();
              System.out.println(list); // [1, 4]
      
              Stream<Integer> stream2 = Stream.of(-2, 1, 2, -5).
                  filter(n -> n > 0).map(n -> n * n);
              Iterable<Integer> iterable = Streams.enhance(stream2).toIterable();
              iterable.forEach(System.out::println); // 1
                                                     // 4
          }
      }
      

      这个想法是使用EnhancedStream 接口,通过定义您要添加的方法来扩展Java 的Stream 接口。然后,动态代理通过将原始 Stream 方法委托给正在适应的实际流来实现此扩展接口,同时它只是为新方法(Stream 中未定义的方法)提供内联实现。

      此代理可通过透明地执行所有代理内容的静态方法获得。

      请注意,我并不是说这是最终解决方案。相反,这只是一个可以高度改进的示例,即对于返回另一个 StreamStream 的每个方法,您也可以为该方法返回一个代理。这将允许链接EnhancedStreams(您需要在EnhancedStream 接口中重新定义这些方法,以便它们返回EnhancedStream 协变返回类型)。此外,缺少正确的异常处理,以及更健壮的代码来决定是否将方法的执行委托给原始流。

      【讨论】:

        【解决方案4】:

        这是一个简单的帮助类,可以让这更容易:

        public class Li {
            public static <T> List<T> st(final Stream<T> stream) {
                return stream.collect(Collectors.toList());
            }
        }
        

        使用示例:

        List<String> lowered = Li.st(Stream.of("HELLO", "WORLD").map(String::toLowerCase));
        

        【讨论】:

        • 如果你打算这样做,你不妨使用 Collectors.toList() 只是为了便于理解。
        猜你喜欢
        • 1970-01-01
        • 2015-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多