Stream API

Java té una API que permet processar seqüències d'objectes mitjançant operacions que es poden afegir a una canonada. Un Stream es genera a partir de col.leccions, arrays o canals d'E/S, i no és modificable: només podem canviar el resultat mitjançant les operacions de la canonada.

Tenim bàsicament dos tipus d'operacions: les intermèdies i les terminals.

  • Operacions intermèdies: permeten afegir operacions addicionals al darrere.
  • Operacions terminals: marquen el final del stream i retornen el resultat.

Les operacions s'encadenen en la canonada mitjançant crides successives que utilitzen expressions lambda. En el següent exemple, s'utilitza l'operació terminal forEach() amb una expressió lambda de tipus Consumer.

List<Integer> list = Arrays.asList(3, 2, 5, 4, 1); Stream<Integer> stream = list.stream(); Consumer<Integer> consumer = (number) -> { System.out.println(number); }; stream.forEach(consumer);

Operacions intermèdies:

  • map: permet aplicar una Function per a canviar el tipus del Stream de T a R

    <R> Stream<R> map(Function<? super T, ? extends R> mapper)

  • flatMap: permet aplicar una Function per a convertir cada T als continguts d'un stream de R

    <R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

  • filter: permet modificar el stream filtrant els elements del Stream amb un Predicate

    Stream<T> filter​(Predicate<? super T> predicate)

  • sorted: permet ordenar els elements amb l'ordre natural (han de ser Comparable)

    Stream<T> sorted()

Operacions terminals:

  • collect: permet reduir els elements amb un Collector<T, A, R>: T és l'entrada, A l'acumulació i R el tipus resultat. Tenim collectors a la classe Collectors.

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

  • forEach: permet executar una acció per cada element.

    void forEach​(Consumer<? super T> action)

  • reduce: permet reduir els elements d'aquest stream utilitzant un BinaryOperator que permet fer T apply(T, T).

    Optional<T> reduce​(BinaryOperator<T> accumulator)

Exemples:

// crear llista de sencers List<Integer> number = Arrays.asList(2, 3, 4, 5); // map List<Integer> square = number.stream() .map(x -> x * x) .collect(Collectors.toList()); System.out.println(square); // flatMap List<Integer> square2 = number.stream() .flatMap(x -> Stream.of(x, x*2)) .collect(Collectors.toList()); System.out.println(square2); // crear llista de strings List<String> names = Arrays.asList("Reflection", "Collection", "Stream"); // filter List<String> result = names.stream() .filter(s -> s.startsWith("S")) .collect(Collectors.toList()); System.out.println(result); // sorted List<String> show = names.stream() .sorted() .collect(Collectors.toList()); System.out.println(show); // crear llista de sencers List<Integer> numbers = Arrays.asList(2, 3, 4, 5, 2); // collect retorna un Set Set<Integer> squareSet = numbers.stream() .map(x -> x * x) .collect(Collectors.toSet()); System.out.println(squareSet); // forEach number.stream() .map(x -> x * x) .forEach(y -> System.out.println(y)); // reduce int even = number.stream() .filter(x -> x % 2 == 0) .reduce(0, (ans, i) -> ans + i); System.out.println(even);