Filtrering af en Java-samling efter en liste

1. Oversigt

Filtrering af en Kollektion ved en Liste er et almindeligt forretningslogisk scenario. Der er mange måder at opnå dette på. Nogle kan dog føre til dårlige løsninger, hvis de ikke gøres ordentligt.

I denne vejledning Vi sammenligner nogle filtreringsimplementeringer og diskuterer deres fordele og ulemper.

2. Brug af en For hver Sløjfe

Vi begynder med den mest klassiske syntaks, en for hver løkke.

Til dette og alle andre eksempler i denne artikel bruger vi følgende klasse:

offentlig klassemedarbejder {privat heltal medarbejdernummer; privat strengnavn; privat heltaleafdelingId; // Standardkonstruktør, getters og settere. }

Vi bruger også følgende metoder til alle eksempler for enkelheds skyld:

privat liste buildEmployeeList () {return Arrays.asList (ny medarbejder (1, "Mike", 1), ny medarbejder (2, "John", 1), ny medarbejder (3, "Mary", 1), ny medarbejder ( 4, "Joe", 2), ny medarbejder (5, "Nicole", 2), ny medarbejder (6, "Alice", 2), ny medarbejder (7, "Bob", 3), ny medarbejder (8, "Scarlett", 3)); } privat liste medarbejdernavnFilter () {returnerer Arrays.asList ("Alice", "Mike", "Bob"); }

I vores eksempel filtrerer vi den første liste over Medarbejdere baseret på den anden liste med Medarbejder navne kun for at finde Medarbejdere med de specifikke navne.

Lad os nu se den traditionelle tilgang - løber gennem begge lister på udkig efter matches:

@Test offentlig ugyldighed givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingForEachLoop () {List filteredList = new ArrayList (); Liste over originalList = buildEmployeeList (); List nameFilter = medarbejdernavnFilter (); for (Medarbejdermedarbejder: originalList) {for (String name: nameFilter) {if (medarbejder.getnavn (). er lig med (navn)) {filteredList.add (medarbejder); // pause; }}} assertThat (filteredList.size (), er (nameFilter.size ())); }

Dette er en simpel syntaks, men det er ret detaljeret og faktisk ret ineffektivt. Kort sagt, det itererer gennem det kartesiske produkt af de to sæt for at få vores svar.

Selv tilføje en pause at afslutte tidligt gentages stadig i samme ordre som et kartesisk produkt i gennemsnit.

Hvis vi kalder størrelsen på medarbejderlisten n, derefter navnFilter vil være på ordren lige så stor, hvilket giver os en O (n2) klassifikation.

3. Brug af streams og Liste nr. Indeholder

Vi omformler den tidligere metode ved at bruge lambdas til at forenkle syntaksen og forbedre læsbarheden. Lad os også bruge Liste nr. Indeholder metode som lambda filter:

@Test offentligt ugyldigt givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambda () {List filteredList; Liste originalList = buildEmployeeList (); List nameFilter = medarbejdernavnFilter (); filteredList = originalList.stream () .filter (medarbejder -> nameFilter.contains (medarbejder.getnavn ())) .collect (Collectors.toList ()); assertThat (filteredList.size (), er (nameFilter.size ())); }

Ved hjælp af Stream API, læsbarheden er forbedret kraftigt, men vores kode forbliver lige så ineffektiv som vores tidligere metode, fordi den er stadig gentager gennem det kartesiske produkt internt. Således har vi det samme O (n2) klassifikation.

4. Brug af streams med HashSet

For at forbedre ydeevnen skal vi bruge HashSet # indeholder metode. Denne metode adskiller sig fra Liste nr. Indeholder fordi det udfører en hash-kode opslag, hvilket giver os et konstant antal operationer:

@Test offentligt ugyldigt givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambdaAndHashSet () {List filteredList; Liste over originalList = buildEmployeeList (); Indstil nameFilterSet = medarbejdernavnFilter (). Stream (). Saml (Collectors.toSet ()); filteredList = originalList.stream () .filter (medarbejder -> nameFilterSet.contains (medarbejder.getnavn ())) .collect (Collectors.toList ()); assertThat (filteredList.size (), er (nameFilterSet.size ())); }

Ved hjælp af HashSet, vores kodeeffektivitet er væsentligt forbedret uden at påvirke læsbarheden. Siden HashSet # indeholder kører i konstant tid, har vi forbedret vores klassifikation til På).

5. Konklusion

I denne hurtige vejledning lærte vi, hvordan man filtrerer en Kollektion ved en Liste af værdier og ulemperne ved at bruge det, der kan virke som den mest ligefremme metode.

Vi skal altid overveje effektivitet, fordi vores kode muligvis ender med at køre i enorme datasæt, og ydelsesproblemer kan have katastrofale konsekvenser i sådanne miljøer.

Al kode præsenteret i denne artikel er tilgængelig på GitHub.