2017-05-05 3 views
4

En Java, existe-t-il un moyen d'appliquer une fonction à tous les éléments d'un flux sans rompre la chaîne de flux? Je sais que je peux appeler forEach, mais cette méthode renvoie un vide, pas un flux.Java 8 applique la fonction à tous les éléments de Stream sans rompre la chaîne de flux

+0

La méthode que vous voulez appeler renvoie-t-elle une valeur? –

+0

pouvez-vous expliquer ce que vous entendez par «sans rompre la chaîne de flux»? peut être un exemple? – Eugene

Répondre

2

Vous recherchez la fonction map() de Stream.

exemple:

List<String> strings = stream 
.map(Object::toString) 
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 
+0

Si j'utilise une carte, je devrai utiliser plusieurs lignes. quelque chose comme myStream.map (obj -> {obj.foo(); return obj;}). Je me demandais s'il y a une solution d'une ligne à cela. – alexgbelov

+0

Vous pouvez également y référer une méthode, vérifiez mon mod. – csenga

0

Je pense que vous cherchez Stream.peek. Mais lisez attentivement les documents, car il a été conçu principalement comme une méthode de débogage. A partir de la documentation:

Cette méthode existe principalement pour soutenir le débogage, où vous voulez voir les éléments comme ils coulent passé un certain point dans un pipeline

L'action passée à peek doit être non interfering.

1

Pas tout à fait sûr de ce que vous entendez par breaking the stream chain, mais toute opération sur un Stream qui retourne une Stream ne sera pas pause ou consommer votre flux. Les flux sont consommés par terminal operations et comme vous l'avez noté le forEachne renvoie pas un Stream<T> et en tant que tel termine le flux, en exécutant toutes les opérations intermediate avant le forEach et le forEach lui-même.

Dans l'exemple que vous avez fourni dans les commentaires:

myStream.map(obj -> {obj.foo(); return obj;} 

Vous ne pouvez pas vraiment faire cela avec une doublure. Bien sûr, vous pouvez utiliser une référence de méthode, mais votre retour Stream serait d'un type différent (en supposant foo retourne un type):

myStream.map(Obj::foo) // this will turn into Stream<T>, where T is 
      // the return type of foo, instead of Stream<Obj> 

Outre que votre opération map est stateful, qui est fortement déconseillée. Votre code compilera et pourrait même fonctionner comme vous le souhaitez - mais il pourrait échouer plus tard. Les opérations map doivent être stateless.

5

Il y a (au moins) 3 façons. Par souci de code exemple, je l'ai supposé que vous voulez appeler 2 méthodes de consommation methodA et methodB:

A. Utilisez peek():

list.stream().peek(x -> methodA(x)).forEach(x -> methodB(x)); 

Bien que les documents disent ne l'utiliser que pour « debug », cela fonctionne (et il est dans la production en ce moment)

B. Utilisez map() pour appeler methodA, puis revenir en arrière l'élément au courant:

list.stream().map(x -> {method1(x); return x;}).forEach(x -> methodB(x)); 

C'est probablement l'approche la plus "acceptable".

C.Deux choses dans le forEach():

list.stream().forEach(x -> {method1(x); methodB(x);}); 

Ceci est la moins flexible et peut ne pas convenir à vos besoins.

+0

Les implications de l'exécution d'une action avec des effets secondaires dans la fonction 'map' et l'utilisation de' peek' pour un tel effet secondaire (non-debug) sont fondamentalement les mêmes. – Holger

+0

@Holger qui a dit quelque chose au sujet des effets secondaires? – Bohemian

+0

L'invocation de 'method1 (x);' serait totalement inutile si elle n'avait pas d'effets secondaires. – Holger

0

La meilleure option que vous avez est d'appliquer la carte à votre flux. qui renvoie un flux constitué par les résultats de l'application de la donnée, la fonction des éléments de ce courant par exemple:

IntStream.rangeClosed(40, 70).limit(20).mapToObj(i -> (Integer) i).map(item->item+3).map(item->item*2)... 

(jet d'articles de type StreamItemABC)

Nous appliquons plusieurs modifications dans le flux mais de cette façon, nous ne pouvons passer aucun argument à la méthode map, pour le réparer:

private void applyMethod(ParameterX parX) { 
someStreamX().map(n -> methodX(n, parX))... 
} 

private StreamItemABC methodX (StreamItemABC item, ParameterX parX) { 
    return notification; 
}