Java >> Java tutorial >  >> Java

Gruppering på flere niveauer med strømme

1. Introduktion

Med Java 8-streams er det ret nemt at gruppere samlinger af objekter baseret på forskellige kriterier. I dette indlæg vil vi se, hvordan vi kan lave fra simple enkeltniveaugrupperinger til mere komplekse, der involverer flere niveauer af grupperinger.

Vi vil bruge to klasser til at repræsentere de objekter, vi vil gruppere efter:person og kæledyr.

Person.class

public class Person {
    private final String name;
    private final String country;
    private final String city;
    private final Pet pet;
    
    public Person(String name, String country, String city, Pet pet) {
        this.name = name;
        this.country = country;
        this.city = city;
        this.pet = pet;
    }
    
    public String getName() {
        return name;
    }
    
    public String getCountry() {
        return country;
    }
    
    public String getCity() {
        return city;
    }
    
    public Pet getPet() {
        return pet;
    }
    
    @Override
    public String toString() {
        return "Person{" +
            "name='" + name + '\'' +
            ", country='" + country + '\'' +
            ", city='" + city + '\'' +
            '}';
    }
}

Pet.class

public class Pet {
    private final String name;
    private final int age;
    
    public Pet(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    @Override
    public String toString() {
        return "Pet{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
    }
}

I hovedmetoden opretter vi den samling, vi vil bruge i de følgende afsnit.

public static void main(String[] args) {
    Person person1 = new Person("John", "USA", "NYC", new Pet("Max", 5));
    Person person2 = new Person("Steve", "UK", "London", new Pet("Lucy", 8));
    Person person3 = new Person("Anna", "USA", "NYC", new Pet("Buddy", 12));
    Person person4 = new Person("Mike", "USA", "Chicago", new Pet("Duke", 10));
    
    List<Person> persons = Arrays.asList(person1, person2, person3, person4);
  • Du kan tage et kig på kildekoden her.

2. Gruppering på enkelt niveau

Den enkleste form for gruppering er gruppering på et niveau. I dette eksempel vil vi gruppere alle personer i samlingen efter deres land:

public void singleLevelGrouping(List<Person> persons) {
    final Map<String, List<Person>> personsByCountry = persons.stream().collect(groupingBy(Person::getCountry));
    
    System.out.println("Persons in USA: " + personsByCountry.get("USA"));
}

Hvis vi tager et kig på kortet, kan vi se, hvordan hvert land indeholder en liste over dets borgere:

Resultatet viser personer, der bor i det angivne land:

Persons in USA: [Person{name='John', country='USA', city='New York'}, Person{name='Anna', country='USA', city='New York'}, Person{name='Mike', country='USA', city='Chicago'}]

3. Gruppering på to niveauer

I dette eksempel vil vi gruppere ikke kun efter land, men også efter by. For at opnå dette er vi nødt til at implementere en gruppering på to niveauer. Vi vil gruppere personer efter land, og for hvert land vil vi gruppere dets personer efter den by, hvor de bor.

For at tillade gruppering på flere niveauer, understøtter groupingBy-metoden i klassen Collectors en ekstra Collector som et andet argument:

 public static <T, K, A, D>
    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream)

Lad os bruge denne metode til at implementere vores gruppering på to niveauer:

 public void twoLevelGrouping(List<Person> persons) {
     final Map<String, Map<String, List<Person>>> personsByCountryAndCity = persons.stream().collect(
         groupingBy(Person::getCountry,
            groupingBy(Person::getCity)
        )
    );
    System.out.println("Persons living in London: " + personsByCountryAndCity.get("UK").get("London").size());
}

Hvis vi fejlretter udførelsen, vil vi se, hvordan folk er fordelt:

4. Gruppering på tre niveauer

I vores sidste eksempel vil vi tage et skridt videre og gruppere folk efter land, by og kæledyrsnavn. Jeg har delt det op i to metoder til læsbarhed:

public void threeLevelGrouping(List<Person> persons) {
    final Map<String, Map<String, Map<String, List<Person>>>> personsByCountryCityAndPetName = persons.stream().collect(
            groupingBy(Person::getCountry,
                groupByCityAndPetName()
            )
    );
    System.out.println("Persons whose pet is named 'Max' and live in NY: " +
        personsByCountryCityAndPetName.get("USA").get("NYC").get("Max").size());
}

private Collector<Person, ?, Map<String, Map<String, List<Person>>>> groupByCityAndPetName() {
    return groupingBy(Person::getCity, groupingBy(p -> p.getPet().getName()));
}

Nu har vi tre indlejrede kort, der indeholder hver liste over personer:

5. Konklusion

Java 8 Collectors API giver os en nem måde at gruppere vores samlinger på. Ved at indlejre samlere kan vi tilføje forskellige lag af grupper for at implementere grupperinger på flere niveauer.

Java tag