【问题标题】:Collect list of Long from Double stream in Java 8从 Java 8 中的 Double 流中收集 Long 列表
【发布时间】:2015-06-11 15:36:29
【问题描述】:

我有以下代码:

List<Long> list = new ArrayList<>();
list.add(4L);
list.add(92L);
list.add(100L);
List<Long> newList = list.stream().map(i -> i * 2.5)
                                  .mapToLong(Double::doubleToRawLongBits)
                                  .collect(Collectors.toList());

这段代码不起作用,编译错误是:

接口java.util.stream.LongStream中的方法collect不能应用于给定类型;
必填:java.util.function.Supplier&lt;R&gt;,java.util.function.ObjLongConsumer&lt;R&gt;,java.util.function.BiConsumer&lt;R,R&gt;
找到:java.util.stream.Collector&lt;java.lang.Object,capture#1 of ?,java.util.List&lt;java.lang.Object&gt;&gt;
原因:无法推断类型变量R (实际参数列表和形式参数列表的长度不同)

我已经尝试了很多收集器的用法,但我仍然无法使其工作。 我做错了什么?

【问题讨论】:

  • 您认为Double.doubleToRawLongBits 到底是做什么的?我想你不知道它的作用......
  • 乘以2.5后变成DoubleStream。
  • @aldrael:不正确。它变成了Stream&lt;Double&gt;,这不是一回事。
  • @LouisWasserman 你能告诉我更多吗?

标签: java java-8 java-stream


【解决方案1】:

mapToLong 给你一个LongStream,它不能被Collectors.toList 编辑为collect

这是因为LongStream

一系列原始长值元素

我们不能有List&lt;long&gt;,我们需要List&lt;Long&gt;。因此,为了能够收集它们,我们首先需要将这些原始 longs 装箱到 Long 对象中:

list.stream().map(i -> i * 2.5)
    .mapToLong(Double::doubleToRawLongBits)
    .boxed()                                //< I added this line
    .collect(Collectors.toList());

boxed 方法为我们提供了一个 Stream&lt;Long&gt;,我们可以将其收集到一个列表中。

使用map 而不是mapToLong 也可以,因为这将导致Steam&lt;Long&gt; 的值被自动装箱:

list.stream().map(i -> i * 2.5)
    .map(Double::doubleToRawLongBits)
    .collect(Collectors.toList());

【讨论】:

  • 这是最好的答案,因为它可以帮助我作为一名刚接触 Java 8 的程序员了解“为什么”。非常感谢!
【解决方案2】:

如果您使用map 而不是mapToLong,这应该可以编译。 (我不确定你想用 doubleToRawLongBits 做什么有什么意义,但这至少可以编译。)

【讨论】:

  • 重点是我想收到 List,但只使用 map() 和 collect() 我收到 List
  • @aldrael:没有。用map 替换mapToLong 可以正常工作。试试吧。
【解决方案3】:

不确定您期望的结果是什么样的,但这会生成一个List&lt;Long&gt;

public void test() {
    List<Long> list = new ArrayList<>();
    list.add(4L);
    list.add(92L);
    list.add(100L);
    List<Long> newList = list.stream()
            // Times 1.5.
            .map(i -> i * 2.5)
            // Grab the long bits.
            .mapToLong(Double::doubleToRawLongBits)
            // Box them.
            .boxed()
            // Make a list.
            .collect(Collectors.toList());
    System.out.println(newList);
}

【讨论】:

  • mapToLong(f).boxed() 完全等同于map(f)
【解决方案4】:

不清楚你为什么要使用doubleToRawLongBits。如果您的问题是与2.5 的乘法产生double 而不是long,则需要类型转换来转换该值,因为doubleToRawLongBits 不是将double 转换为long 的规范方法。相反,此方法返回值的 IEEE 754 表示,这仅在非常特殊的情况下才有意义。请注意,您可以直接在第一个 map 操作中执行转换:

List<Long> list = new ArrayList<>();
list.add(4L);
list.add(92L);
list.add(100L);

List<Long> newList = list.stream().map(i -> (long)(i * 2.5))
                         .collect(Collectors.toList());

如果您真的想要 double 值的 IEEE 754 表示,这甚至适用:

List<Long> newList = list.stream().map(i -> Double.doubleToRawLongBits(i * 2.5))
                         .collect(Collectors.toList());

但请注意,如果您有一个类型与结果类型匹配的临时列表,您可以就地执行操作,而不是创建两个列表(并通过Stream API):

List<Long> list = new ArrayList<>();
list.add(4L);
list.add(92L);
list.add(100L);
list.replaceAll(i -> (long)(i * 2.5));

同样,即使 如果 你想要 IEEE 754 位,这同样适用:

List<Long> list = new ArrayList<>();
list.add(4L);
list.add(92L);
list.add(100L);
list.replaceAll(i -> Double.doubleToRawLongBits(i * 2.5));

如果您坚持使用Stream API,您可以使用构建器而不是ArrayList 作为源数据:

Stream.Builder<Long> b = Stream.builder();
b.add(4L);
b.add(92L);
b.add(100L);
List<Long> newList = b.build().map(i -> (long)(i * 2.5))
                      .collect(Collectors.toList());
newList.forEach(System.out::println);

【讨论】:

    【解决方案5】:

    这个问题的本质是函数mapToLong的返回值是LongStream接口。 LongStream 只有方法

     <R> R collect(Supplier<R> supplier,
                   ObjLongConsumer<R> accumulator,
                   BiConsumer<R, R> combiner);
    

    你可能想使用方法

    <R, A> R collect(Collector<? super T, A, R> collector);
    

    您可以在java.util.stream.Stream 类中找到此方法。

    LongStreamStream 没有扩展关系。

    【讨论】:

      【解决方案6】:
          HashMap<String, Map<String, Long>> map = new HashMap<>();
      
          List<Entry<String, Map<String, Long>>> sortedList = map
          .entrySet()
          .stream()
          .sorted((a, b) -> Long.compare(
                                         a.getValue().values().stream().mapToLong(l -> l).sum(),
                                         b.getValue().values().stream().mapToLong(l -> l).sum()))
      
          .collect(Collectors.toList());
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-13
        • 2015-08-30
        • 2017-09-26
        相关资源
        最近更新 更多