web-dev-qa-db-fra.com

Récupération d'une liste d'un fichier Java.util.stream.Stream dans Java 8

Je jouais avec Java 8 lambdas pour filtrer facilement les collections. Mais je n'ai pas trouvé de moyen concis pour récupérer le résultat sous la forme d'une nouvelle liste dans la même déclaration. Voici mon approche la plus concise à ce jour:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = new ArrayList<>();
sourceLongList.stream().filter(l -> l > 100).forEach(targetLongList::add);

Les exemples sur le net n'ont pas répondu à ma question car ils arrêtaient sans générer une nouvelle liste de résultats. Il doit y avoir un moyen plus concis. J'aurais pensé que la classe Stream avait des méthodes telles que toList(), toSet(),…

Existe-t-il un moyen de pouvoir affecter directement les variables targetLongList par la troisième ligne?

421
Daniel K.

Ce que vous faites peut être la manière la plus simple, à condition que votre flux reste séquentiel - sinon vous devrez passer un appel à sequential () avant forEach.

[Éditer plus tard: la raison pour l’appel de sequential () est nécessaire, c’est que le code tel qu’il est (forEach(targetLongList::add)) serait trop volumineux si le flux était parallèle. Même dans ce cas, il n'atteindra pas l'effet escompté, car forEach est explicitement non déterministe - même dans un flux séquentiel, l'ordre de traitement des éléments n'est pas garanti. Vous devez utiliser forEachOrdered pour assurer un bon ordre. L'intention des concepteurs de l'API Stream est que vous utilisiez le collecteur dans cette situation, comme ci-dessous.]

Une alternative est

targetLongList = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(Collectors.toList());
584
Maurice Naftalin

Mis à jour:

Une autre approche consiste à utiliser Collectors.toList:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toList());

Solution précédente:

Une autre approche consiste à utiliser Collectors.toCollection:

targetLongList = 
    sourceLongList.stream().
    filter(l -> l > 100).
    collect(Collectors.toCollection(ArrayList::new));
169
MohamedSanaulla

J'aime utiliser une méthode util qui renvoie un collecteur pour ArrayList lorsque c'est ce que je veux.

Je pense que la solution utilisant Collectors.toCollection(ArrayList::new) est un peu trop bruyante pour une opération aussi courante.

Exemple:

ArrayList<Long> result = sourceLongList.stream()
    .filter(l -> l > 100)
    .collect(toArrayList());

public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
    return Collectors.toCollection(ArrayList::new);
}

Avec cette réponse, je souhaite également montrer à quel point il est simple de créer et d'utiliser des collecteurs personnalisés, ce qui est très utile en général.

12
Lii

Si vous avez un tableau de primitives, vous pouvez utiliser les collections de primitives disponibles dans Eclipse Collections .

LongList sourceLongList = LongLists.mutable.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
LongList targetLongList = sourceLongList.select(l -> l > 100);

Si vous ne pouvez pas modifier la sourceLongList à partir de List:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = 
    ListAdapter.adapt(sourceLongList).select(l -> l > 100, new ArrayList<>());

Si vous voulez utiliser LongStream:

long[] sourceLongs = new long[]{1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L};
LongList targetList = 
    LongStream.of(sourceLongs)
    .filter(l -> l > 100)
    .collect(LongArrayList::new, LongArrayList::add, LongArrayList::addAll);

Remarque: je contribue aux collections Eclipse.

5
Nikhil Nanivadekar

Un moyen un peu plus efficace (évitez la création de la liste source et le désemballage automatique par le filtre):

List<Long> targetLongList = LongStream.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L)
    .filter(l -> l > 100)
    .boxed()
    .collect(Collectors.toList());
4
msayag
collect(Collectors.toList());

C'est l'appel que vous pouvez utiliser pour convertir n'importe quel flux en liste.

3
Pramod

Si vous voulez bien utiliser des bibliothèques tierces, les cyclops-react lib d'AOL (divulguer que je suis un contributeur) possède des extensions pour tous les types JDK Collection , y compris Liste . L'interface ListX étend Java.util.List et ajoute un grand nombre d'opérateurs utiles, y compris un filtre.

Vous pouvez simplement écrire

ListX<Long> sourceLongList = ListX.of(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
ListX<Long> targetLongList = sourceLongList.filter(l -> l > 100);

ListX peut également être créé à partir d'une liste existante (via ListX.fromIterable)

1
John McClean

Il existe une autre variante de la méthode collect fournie par la classe LongStream et, de la même manière, par les classes IntStream et DoubleStream.

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

Effectue une opération de réduction mutable sur les éléments de ce flux. Une réduction modifiable est une réduction dans laquelle la valeur réduite est un conteneur de résultat modifiable, tel qu'un ArrayList, et les éléments sont incorporés en mettant à jour l'état du résultat plutôt qu'en remplaçant le résultat. Cela produit un résultat équivalent à:

R result = supplier.get();
  for (long element : this stream)
       accumulator.accept(result, element);
  return result;

Tout comme reduction (long, LongBinaryOperator), les opérations de collecte peuvent être parallélisées sans nécessiter de synchronisation supplémentaire. Il s'agit d'une opération de terminal.

Et répondre à votre question avec cette méthode de collecte est comme ci-dessous:

    LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, (list, value) -> list.add(value)
    , (list1, list2) -> list1.addAll(list2));

Vous trouverez ci-dessous la variante de référence de la méthode qui est assez intelligente, mais qui est difficile à comprendre:

     LongStream.of(1L, 2L, 3L, 3L).filter(i -> i > 2)
    .collect(ArrayList::new, List::add , List::addAll);

Vous trouverez ci-dessous la variante HashSet:

     LongStream.of(1L, 2L, 3L, 3).filter(i -> i > 2)
     .collect(HashSet::new, HashSet::add, HashSet::addAll);

De même la variante LinkedList est comme ceci:

     LongStream.of(1L, 2L, 3L, 3L)
     .filter(i -> i > 2)
     .collect(LinkedList::new, LinkedList::add, LinkedList::addAll);
1
Vaneet Kataria

Vous pouvez réécrire le code comme ci-dessous:

List<Long> sourceLongList = Arrays.asList(1L, 10L, 50L, 80L, 100L, 120L, 133L, 333L);
List<Long> targetLongList = sourceLongList.stream().filter(l -> l > 100).collect(Collectors.toList());
0
Pratik Pawar

Si quelqu'un (comme moi) cherche des moyens de traiter les objets au lieu de types primitifs, utilisez mapToObj()

String ss = "An alternative way is to insert the following VM option before "
        + "the -vmargs option in the Eclipse shortcut properties(edit the "
        + "field Target inside the Shortcut tab):";

List<Character> ll = ss
                        .chars()
                        .mapToObj(c -> new Character((char) c))
                        .collect(Collectors.toList());

System.out.println("List type: " + ll.getClass());
System.out.println("Elem type: " + ll.get(0).getClass());
ll.stream().limit(50).forEach(System.out::print);

impressions:

List type: class Java.util.ArrayList
Elem type: class Java.lang.Character
An alternative way is to insert the following VM o
0
Kashyap
String joined = 
                Stream.of(isRead?"read":"", isFlagged?"flagged":"", isActionRequired?"action":"", isHide?"hide":"")
                      .filter(s -> s != null && !s.isEmpty())
                      .collect(Collectors.joining(","));
0
sharath

Voici le code par AbacusUtil

LongStream.of(1, 10, 50, 80, 100, 120, 133, 333).filter(e -> e > 100).toList();

Divulgation: Je suis le développeur de AbacusUtil.

0
user_3380739