在Java 8中从Double流中收集Long列表

时间:2015-06-11 15:36:29

标签: java java-8 java-stream

我有以下代码:

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());

此代码不起作用,编译错误为:

  接口collect中的

方法java.util.stream.LongStream无法应用于给定类型;     
必填:java.util.function.Supplier<R>,java.util.function.ObjLongConsumer<R>,java.util.function.BiConsumer<R,R>     
发现:java.util.stream.Collector<java.lang.Object,capture#1 of ?,java.util.List<java.lang.Object>>     
原因:无法推断类型变量R       (实际和正式的参数列表长度不同)

我尝试了许多收藏家的用法,但我仍然无法使其发挥作用。 我做错了什么?

6 个答案:

答案 0 :(得分:34)

mapToLong为您提供了一个LongStreamcollect无法Collectors.toList编辑。

这是因为LongStream

  

一系列原始长值元素

我们不能拥有List<long>,我们需要List<Long>。因此,为了能够收集它们,我们首先需要将这些原始long封装到Long个对象中:

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

boxed方法为我们提供了Stream<Long>,我们可以将其收集到列表中。

根据map的建议,使用Louis Wasserman而不是mapToLong也会有效,因为这样会产生Steam<Long>,其中的值会自动加框:

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

答案 1 :(得分:15)

如果您使用map而不是mapToLong,则应编译。 (我不确定你试图用doubleToRawLongBits做什么是有道理的,但这至少会编译。)

答案 2 :(得分:5)

不确定您希望结果如何,但这会产生List<Long>

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);
}

答案 3 :(得分:1)

目前尚不清楚为什么要使用doubleToRawLongBits。如果问题是与2.5的乘法产生double而不是long,则需要使用类型转换来转换值,因为doubleToRawLongBits不是规范的转换方式doublelong。相反,此方法返回值的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);

答案 4 :(得分:1)

这个问题的实质是函数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没有延伸关系。

答案 5 :(得分:0)

    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());