Komparator og sammenlignelig i Java

1. Introduktion

Sammenligning i Java er ret let - indtil de ikke er det.

Når vi arbejder med brugerdefinerede typer eller prøver at sammenligne objekter, der ikke er direkte sammenlignelige, skal vi bruge en sammenligningsstrategi. Vi kan bygge en simpel, men ved hjælp af Komparator eller Sammenlignelig grænseflader.

2. Opsætning af eksemplet

Lad os tage et eksempel på et fodboldhold - hvor vi vil stille spillerne op efter deres placering.

Vi starter med at oprette en simpel Spiller klasse:

offentlig klassespiller {privat int-ranking; privat strengnavn; privat int alder // konstruktør, getters, setters}

Lad os derefter oprette en PlayerSorter klasse for at oprette vores samling og forsøge at sortere den ved hjælp af Collections.sort:

public static void main (String [] args) {List footballTeam = new ArrayList (); Player player1 = ny spiller (59, "John", 20); Player player2 = ny spiller (67, "Roger", 22); Player player3 = ny spiller (45, "Steven", 24); footballTeam.add (spiller1); footballTeam.add (spiller2); footballTeam.add (spiller3); System.out.println ("Før sortering:" + footballTeam); Collections.sort (footballTeam); System.out.println ("Efter sortering:" + footballTeam); } 

Her resulterer dette som forventet i en kompileringstidsfejl:

Metodesorteringen (Liste) i typen Samlinger kan ikke anvendes til argumenterne (ArrayList)

Lad os forstå, hvad vi gjorde forkert her.

3. Sammenlignelig

Som navnet antyder, Sammenlignelig er en grænseflade, der definerer en strategi for at sammenligne et objekt med andre objekter af samme type. Dette kaldes klassens ”naturlige ordning”.

Derfor skal vi definere vores for at kunne sortere Spiller objekt som sammenligneligt ved at implementere Sammenlignelig grænseflade:

public class Player implementer Comparable {// same as before @Override public int compareTo (Player otherPlayer) {return Integer.compare (getRanking (), otherPlayer.getRanking ()); }} 

Sorteringsordren bestemmes af returværdien af sammenligne med()metode. Det Heltal. Sammenligne (x, y) returnerer -1 hvis x er mindre end y, returnerer 0, hvis de er ens, og returnerer 1 ellers.

Metoden returnerer et tal, der angiver, om det objekt, der sammenlignes, er mindre end, lig med eller større end det objekt, der sendes som et argument.

Endelig når vi kører vores PlayerSorter nu kan vi se vores Spillere sorteret efter deres placering:

Før sortering: [John, Roger, Steven] Efter sortering: [Steven, John, Roger]

Nu hvor vi har en klar forståelse af naturlig bestilling med Sammenlignelig, Lad os se hvordan vi kan bruge andre typer ordrer på en mere fleksibel måde end direkte implementering af en grænseflade.

4. Komparator

Det Komparator interface definerer en sammenlign (arg1, arg2) metode med to argumenter, der repræsenterer sammenlignede objekter og fungerer på samme måde som Comparable.compareTo () metode.

4.1. Opretter Komparatorer

At oprette en Komparator, vi er nødt til at gennemføre Komparator interface.

I vores første eksempel opretter vi en Komparator at bruge placering attribut for Spiller at sortere spillerne:

offentlig klasse PlayerRankingComparator implementerer Comparator {@Override public int sammenlign (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getRanking (), secondPlayer.getRanking ()); }}

På samme måde kan vi oprette en Komparator at bruge alder attribut for Spiller at sortere spillerne:

offentlig klasse PlayerAgeComparator implementerer Comparator {@Override public int compare (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getAge (), secondPlayer.getAge ()); }}

4.2. Komparatorer i aktion

Lad os ændre vores for at demonstrere konceptet PlayerSorter ved at introducere et andet argument til Collections.sort-metode som faktisk er forekomsten af Komparator vi vil bruge.

Ved hjælp af denne tilgang kan vi tilsidesætte den naturlige rækkefølge:

PlayerRankingComparator playerComparator = ny PlayerRankingComparator (); Collections.sort (footballTeam, playerComparator); 

Lad os nu køre vores PlayerRankingSorter til se resultatet:

Før sortering: [John, Roger, Steven] Efter sortering efter rangering: [Steven, John, Roger]

Hvis vi ønsker en anden sorteringsrækkefølge, behøver vi kun ændre Komparator vi bruger:

PlayerAgeComparator playerComparator = ny PlayerAgeComparator (); Collections.sort (footballTeam, playerComparator);

Nu, når vi kører vores PlayerAgeSorter, kan vi se en anden sorteringsrækkefølge efter alder:

Før sortering: [John, Roger, Steven] Efter sortering efter alder: [Roger, John, Steven]

4.3. Java 8 Komparatorer

Java 8 giver nye måder at definere på Komparatorer ved hjælp af lambda-udtryk og sammenligne () statisk fabriksmetode.

Lad os se et hurtigt eksempel på, hvordan man bruger et lambda-udtryk til at oprette en Komparator:

Comparator byRanking = (Player player1, Player player2) -> Integer.compare (player1.getRanking (), player2.getRanking ());

Det Comparator. Sammenligning metoden tager en metode til beregning af egenskaben, der vil blive brugt til at sammenligne varer, og returnerer en matching Komparator eksempel:

Comparator byRanking = Comparator .comparing (Player :: getRanking); Comparator byAge = Comparator .comparing (Player :: getAge);

Du kan udforske Java 8-funktionaliteten i dybden i vores Java 8 Comparator. Sammenligningsvejledning.

5. Komparator vs. Sammenlignelig

Det Sammenlignelig interface er et godt valg, når det bruges til at definere standardbestilling eller med andre ord, hvis det er den vigtigste måde at sammenligne objekter på.

Derefter må vi spørge os selv, hvorfor bruge en Komparator hvis vi allerede har Sammenlignelig?

Der er flere grunde til:

  • Nogle gange kan vi ikke ændre kildekoden for den klasse, hvis objekter vi vil sortere, hvilket gør brug af Sammenlignelig umulig
  • Ved brug af Komparatorer giver os mulighed for at undgå at tilføje yderligere kode til vores domæneklasser
  • Vi kan definere flere forskellige sammenligningsstrategier, hvilket ikke er muligt, når du bruger Sammenlignelig

6. Undgå subtraktionstricket

I løbet af denne vejledning brugte vi Integer.compare () metode til at sammenligne to heltal. Man kan argumentere for, at vi i stedet skal bruge denne kloge one-liner:

Komparator komparator = (p1, p2) -> p1.getRanking () - p2.getRanking ();

Selvom det er meget mere kortfattet sammenlignet med andre løsninger, kan det blive offer for heltal overløb i Java:

Player player1 = ny Player (59, "John", Integer.MAX_VALUE); Player player2 = ny spiller (67, "Roger", -1); Liste spillere = Arrays.asList (player1, player2); players.sort (komparator);

Da -1 er meget mindre end Heltal.MAX_VALUE, "Roger" skulle komme før "John" i den sorterede samling. På grund af heltalsoverløb er “Heltal.MAX_VALUE - (-1)” vil være mindre end nul. Så baseret på Komparator / sammenlignelig kontrakt, den Heltal.MAX_VALUE er mindre end -1, hvilket naturligvis er forkert.

Derfor, på trods af hvad vi forventede, kommer "John" foran "Roger" i den sorterede samling:

assertEquals ("John", players.get (0) .getName ()); assertEquals ("Roger", players.get (1) .getName ());

7. Konklusion

I denne vejledning undersøgte vi Sammenlignelig og Komparator grænseflader og drøftede forskellene mellem dem.

For at forstå mere avancerede emner for sortering, se vores andre artikler såsom Java 8 Comparator, Java 8 Comparison with Lambdas.

Og som normalt kan kildekoden findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found