Cómo utilizar un colector de encargo en una operación groupingBy

Tim Biegeleisen:

Los senderos de Oracle en la reducción de las corrientes da un ejemplo de cómo convertir una colección de gente en un mapa que contiene la edad media basada en el género. Se utiliza la siguiente Personclase y código:

public class Person {
    private int age;

    public enum Sex {
        MALE,
        FEMALE
    }

    private Sex sex;

    public Person (int age, Sex sex) {
        this.age = age;
        this.sex = sex;
    }

    public int getAge() { return this.age; }

    public Sex getSex() { return this.sex; }
}

Map<Person.Sex, Double> averageAgeByGender = roster
    .stream()
    .collect(
        Collectors.groupingBy(
            Person::getSex,                      
            Collectors.averagingInt(Person::getAge)));

El código corriente arriba funciona muy bien, pero quería ver cómo se hace la misma operación mientras se utiliza un encargo de ejecución de un colector. He podido encontrar ningún ejemplo completo de cómo hacer esto ya sea en desbordamiento de pila o de la red. En cuanto a la razón por lo que se quiere hacer esto, como un ejemplo, tal vez nos gustaría para calcular algún tipo de promedio ponderado que involucra la edad. En este caso, el comportamiento predeterminado de Collectors.averagingIntno sería suficiente.

Didier L:

Sólo tiene que utilizar Collector.of(Supplier, BiConsumer, BinaryOperator, [Function,] Characteristics...)para esos casos:

Collector.of(() -> new double[2],
        (a, t) -> { a[0] += t.getAge(); a[1]++; },
        (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
        a -> (a[1] == 0) ? 0.0 : a[0] / a[1])
)

Aunque podría ser más legible para definir una PersonAverager:

class PersonAverager {
    double sum = 0;
    int count = 0;

    void accept(Person p) {
        sum += p.getAge();
        count++;
    }

    PersonAverager combine(PersonAverager other) {
        sum += other.sum;
        count += other.count;
        return this;
    }

    double average() {
        return count == 0 ? 0 : sum / count;
    }
}

y utilizarlo como:

Collector.of(PersonAverager::new,
        PersonAverager::accept,
        PersonAverager::combine,
        PersonAverager::average)

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=184748&siteId=1
Recomendado
Clasificación