在Java8中从双流中收集Long列表

Collect list of Long from Double stream in Java 8

我有以下代码:

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

此代码无效,编译错误为:

method collect in interface java.util.stream.LongStream cannot be applied to given types;
required: java.util.function.Supplier<R>,java.util.function.ObjLongConsumer<R>,java.util.function.BiConsumer<R,R>
found: java.util.stream.Collector<java.lang.Object,capture#1 of ?,java.util.List<java.lang.Object>>
reason: cannot infer type-variable(s) R (actual and formal argument lists differ in length)

我已经尝试了 Collectors 的多种用法,但仍然无法正常工作。 我做错了什么?

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

不确定您期望的结果是什么样的,但这会生成 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);
}

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

mapToLong gives you a LongStream which is not able to be collect-ed by Collectors.toList.

这是因为LongStream

A sequence of primitive long-valued elements

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

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

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

使用 map 而不是 mapToLong 也可以,因为这会导致 Steam<Long> 值自动装箱:

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

这个问题的实质是函数mapToLong的return值是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 class 中找到此方法。

LongStreamStream没有扩展关系。

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