Dominando las Operaciones Intermedias y Terminales de Java Stream API

Clasificado en Informática

Escrito el en español con un tamaño de 4,41 KB

Referencia de Operaciones de la API Stream de Java

La API Stream de Java facilita el procesamiento funcional de colecciones de datos. Sus operaciones se dividen en dos categorías principales: intermedias y terminales.

Operaciones Intermedias

Las operaciones intermedias devuelven un nuevo Stream, permitiendo encadenar múltiples operaciones. Son de ejecución perezosa (lazy).

distinct
Devuelve un stream con los elementos distintos.
filter
Devuelve un stream con los elementos que cumplen el predicado.
flatMap
Devuelve un stream con el resultado de aplicar una función sobre los elementos del stream. La función produce un stream por cada elemento, que se aplana.
limit
Devuelve un stream de longitud menor o igual que el límite que se le pasa.
map
Devuelve un stream con el resultado de aplicar una función sobre los elementos del stream.
peek
Devuelve este stream, pero aplica una acción al consumir elementos (útil para debugging).
skip
Descarta los n primeros elementos y devuelve el stream con los siguientes.
sorted
Devuelve un stream ordenado de acuerdo al orden natural o a un Comparator.

Operaciones Terminales

Las operaciones terminales inician el procesamiento del stream y producen un resultado final o un efecto secundario. Después de una operación terminal, el stream no puede ser reutilizado.

allMatch
Devuelve true si todos los elementos del stream cumplen el predicado.
anyMatch
Devuelve true si algún elemento del stream cumple el predicado.
findAny
Devuelve un elemento del stream. Se devuelve un Optional vacío si el stream está vacío.
findFirst
Devuelve el primer elemento del stream (si está desordenado, es uno arbitrario).
noneMatch
Devuelve true si ningún elemento del stream cumple el predicado.
forEach
Aplica una acción a cada elemento del stream.
reduce
Aplica una operación de reducción que calcula un valor único para el stream.

Ejemplos de Implementación y Utilidades Avanzadas

Ejemplo de Reducción y Observación con peek

Este ejemplo demuestra cómo encadenar operaciones intermedias (peek, filter, map) antes de la operación terminal reduce para calcular la suma de los cuadrados de los números impares.


int sum = Stream.of(1, 2, 3, 4, 5)
    .peek(e -> System.out.println("Taking integer: " + e))
    .filter(n -> n % 2 == 1)
    .peek(e -> System.out.println("Filtered integer: " + e))
    .map(n -> n * n)
    .peek(e -> System.out.println("Mapped integer: " + e))
    .reduce(0, Integer::sum);

Implementación de Predicados Personalizados y Herramientas de Filtrado

Las siguientes clases de utilidad permiten crear y combinar lógicas de filtrado complejas utilizando la interfaz Predicate.


class TestSet<T> implements Predicate<T> {
    public Set<T> set;

    public TestSet(Collection<T> c) {
        this.set = new HashSet<T>(c);
    }

    @Override
    public boolean test(T t) {
        return this.set.contains(t);
    }
}

class STools {
    /**
     * Filtra un stream aplicando una combinación OR de múltiples predicados.
     */
    public static <T> Stream<T> filterOr(Stream<T> s, Predicate<T>... ps) {
        Predicate<T> combinedPred = x -> false;
        for (Predicate<T> p : ps) {
            combinedPred = combinedPred.or(p);
        }
        return s.filter(combinedPred);
    }

    /**
     * Filtra un stream si el elemento está contenido en cualquiera de los conjuntos proporcionados.
     */
    public static <T> Stream<T> filterSets(Stream<T> s, Set<T>... sets) {
        return s.filter(t -> {
            for (Set<T> p : sets) {
                if (p.contains(t)) return true;
            }
            return false;
        });
    }
}

Entradas relacionadas: