Соберите список Long from Double stream в 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());
Этот код не работает, и ошибка компиляции:
Метод 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
(фактические и формальные списки аргументов различаются по длине)
Я испробовал много способов использования Коллекционеров, но я до сих пор не могу заставить его работать. Что я делаю неправильно?
Ответы
Ответ 1
mapToLong
дает вам LongStream
, который не может быть collect
-ed на 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
вместо mapToLong
, как предложил Луи Вассерман, также будет работать, потому что это приведет к появлению Steam<Long>
котором значения будут автоматически упакованы:
list.stream().map(i -> i * 2.5)
.map(Double::doubleToRawLongBits)
.collect(Collectors.toList());
Ответ 2
Это должно скомпилироваться, если вы используете map
вместо mapToLong
. (Я не уверен, что вы пытаетесь сделать с doubleToRawLongBits
, имеет смысл, но это, по крайней мере, скомпилируется.)
Ответ 3
Не уверен, что вы ожидаете, что ваши результаты будут похожи, но это создает 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);
}
Ответ 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());
Это даже применяется, если вы действительно хотите представление IEEE 754 значений double
:
List<Long> newList = list.stream().map(i -> Double.doubleToRawLongBits(i * 2.5))
.collect(Collectors.toList());
Но учтите, что если у вас есть временный список, тип которого соответствует типу результата, вы можете выполнить операцию на месте вместо создания двух списков (и пройти через API Stream
):
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));
Если вы настаиваете на использовании API Stream
, вы можете использовать построитель вместо 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.
LongStream
и Stream
имеют расширенных отношений.
Ответ 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());