web-dev-qa-db-fra.com

Collectez la liste des flux Long from Double dans Java 8

J'ai le code suivant:

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

Ce code ne fonctionne pas et l'erreur de compilation est:

méthode collect dans l'interface Java.util.stream.LongStream ne peut pas être appliqué à des types donnés;
obligatoire: Java.util.function.Supplier<R>,Java.util.function.ObjLongConsumer<R>,Java.util.function.BiConsumer<R,R>
a trouvé: Java.util.stream.Collector<Java.lang.Object,capture#1 of ?,Java.util.List<Java.lang.Object>>
raison: ne peut pas déduire les variables de type R (les listes d'arguments réelles et formelles diffèrent en longueur)

J'ai essayé de nombreuses utilisations des collecteurs mais je ne peux toujours pas le faire fonctionner. Qu'est-ce que je fais mal?

21
aldrael

mapToLong vous donne un LongStream qui ne peut pas être collect - ed par Collectors.toList .

C'est parce que LongStream est

Une séquence d'éléments primitifs à valeur longue

Nous ne pouvons pas avoir un List<long>, nous avons besoin d'un List<Long>. Par conséquent, pour pouvoir les collecter, nous devons d'abord mettre ces longs primitifs dans des objets Long:

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

La méthode boxed nous donne un Stream<Long> que nous pouvons rassembler dans une liste.

Utiliser map plutôt que mapToLong, comme suggéré par Louis Wasserman , fonctionnera également car cela entraînera un Steam<Long> où les valeurs sont automatiquement encadrées:

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

Cela devrait se compiler si vous utilisez map au lieu de mapToLong. (Je ne sais pas ce que vous essayez de faire avec doubleToRawLongBits est logique, mais cela compilera au moins.)

15
Louis Wasserman

Je ne sais pas à quoi vous vous attendez, mais cela génère un 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);
}
5
OldCurmudgeon

L'essence de ce problème est que la valeur de retour de la fonction mapToLong est LongStream interface. LongStream n'a qu'une méthode

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

Vous voudrez peut-être utiliser la méthode

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

Vous pouvez trouver cette méthode dans la classe Java.util.stream.Stream .

LongStream et Stream n'ont pas de relation d'extension.

1
Monet

La raison pour laquelle vous souhaitez utiliser doubleToRawLongBits n'est pas claire. Si votre problème est que la multiplication par 2.5 produit double plutôt que long, vous avez besoin d'un transtypage de type pour convertir la valeur, car doubleToRawLongBits n'est pas la manière canonique de convertir double en long. Au lieu de cela, cette méthode renvoie la représentation IEEE 754 de la valeur qui n'est intéressante que dans des cas très spéciaux. Notez que vous pouvez effectuer la conversion directement dans la première opération 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());

Cela s'applique même si vous voulez vraiment la représentation IEEE 754 des valeurs double:

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

Mais notez que si vous avez une liste temporaire dont le type correspond au type de résultat, vous pouvez effectuer l'opération sur place au lieu de créer deux listes (et en passant par l'API Stream):

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

encore une fois, la même chose s'applique même si vous voulez IEEE 754 bits:

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

Si vous insistez pour utiliser l'API Stream, vous pouvez utiliser le générateur plutôt qu'un ArrayList pour les données source:

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);
1
Holger
    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());
0
JavaMan