Comparator en vergelijkbaar in Java

1. Inleiding

Vergelijkingen in Java zijn vrij eenvoudig - totdat ze dat niet zijn.

Als we met aangepaste typen werken of objecten proberen te vergelijken die niet direct vergelijkbaar zijn, moeten we een vergelijkingsstrategie gebruiken. We kunnen er eenvoudig een bouwen, maar gebruikmakend van de Comparator of Vergelijkbaar interfaces.

2. Het voorbeeld opstellen

Laten we een voorbeeld nemen van een voetbalteam - waar we de spelers willen rangschikken op hun ranglijst.

We beginnen met het maken van een eenvoudig Speler klasse:

openbare klasse Speler {privé int ranking; private String naam; privé int leeftijd; // constructor, getters, setters}

Laten we vervolgens een PlayerSorter class om onze collectie te maken en een poging te doen om deze te sorteren met Collections.sort:

public static void main (String [] args) {List footballTeam = new ArrayList (); Player player1 = nieuwe speler (59, "Jan", 20); Player player2 = nieuwe speler (67, "Roger", 22); Player player3 = nieuwe speler (45, "Steven", 24); footballTeam.add (speler1); footballTeam.add (speler2); footballTeam.add (speler3); System.out.println ("Voor sorteren:" + footballTeam); Collections.sort (footballTeam); System.out.println ("Na sortering:" + footballTeam); } 

Hier resulteert dit, zoals verwacht, in een compilatietijdfout:

De methode sort (List) in het type Collections is niet van toepassing op de argumenten (ArrayList)

Laten we begrijpen wat we hier fout hebben gedaan.

3. Vergelijkbaar

Zoals de naam al doet vermoeden, Vergelijkbaar is een interface die een strategie definieert om een ​​object te vergelijken met andere objecten van hetzelfde type. Dit wordt de "natuurlijke ordening" van de klas genoemd.

Dienovereenkomstig, om te kunnen sorteren - moeten we onze definiëren Speler object vergelijkbaar door het implementeren van het Vergelijkbaar koppel:

public class Player implementeert Comparable {// hetzelfde als voorheen @Override public int CompareTo (Player otherPlayer) {return Integer.compare (getRanking (), otherPlayer.getRanking ()); }} 

De sorteervolgorde wordt bepaald door de retourwaarde van de vergelijk met()methode. De Geheel getal. Pare (x, y) geeft -1 terug als X is minder dan y, geeft 0 terug als ze gelijk zijn en geeft anders 1 terug.

De methode retourneert een getal dat aangeeft of het object dat wordt vergeleken kleiner is dan, gelijk aan of groter is dan het object dat als argument wordt doorgegeven.

Eindelijk, wanneer we onze PlayerSorter nu kunnen we onze zien Spelers gesorteerd op hun ranglijst:

Voor het sorteren: [John, Roger, Steven] Na het sorteren: [Steven, John, Roger]

Nu we een duidelijk begrip hebben van natuurlijke ordening met Vergelijkbaar, laten we kijken hoe we andere soorten bestellingen op een meer flexibele manier kunnen gebruiken dan het direct implementeren van een interface.

4. Comparator

De Comparator interface definieert een vergelijk (arg1, arg2) methode met twee argumenten die de vergeleken objecten vertegenwoordigen en op dezelfde manier werken als de Vergelijkbaar.compareTo () methode.

4.1. Creëren Vergelijkers

Om een Comparator, we moeten het Comparator koppel.

In ons eerste voorbeeld maken we een Comparator om de rangschikking kenmerk van Speler om de spelers te sorteren:

openbare klasse PlayerRankingComparator implementeert Comparator {@Override public int Compare (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getRanking (), secondPlayer.getRanking ()); }}

Evenzo kunnen we een Comparator om de leeftijd kenmerk van Speler om de spelers te sorteren:

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

4.2. Vergelijkers in actie

Laten we om het concept te demonstreren onze PlayerSorter door een tweede argument toe te voegen aan de Collections.sort methode dat is eigenlijk de instantie van Comparator we willen gebruiken.

Door deze aanpak te gebruiken, kunnen we de natuurlijke ordening opheffen:

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

Laten we nu onze gang gaan PlayerRankingSorter naar zie het resultaat:

Voor het sorteren: [John, Roger, Steven] Na het sorteren op rangschikking: [Steven, John, Roger]

Als we een andere sorteervolgorde willen, hoeven we alleen de Comparator we gebruiken:

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

Nu, als we onze PlayerAgeSorter, kunnen we een andere sorteervolgorde zien op leeftijd:

Voor het sorteren: [John, Roger, Steven] Na het sorteren op leeftijd: [Roger, John, Steven]

4.3. Java 8 Vergelijkers

Java 8 biedt nieuwe manieren om te definiëren Vergelijkers door lambda-uitdrukkingen en de vergelijken () statische fabrieksmethode.

Laten we een snel voorbeeld bekijken van hoe je een lambda-expressie kunt gebruiken om een Comparator:

Vergelijker byRanking = (Speler speler1, Speler speler2) -> Geheel getal.compare (speler1.getRanking (), speler2.getRanking ());

De Comparator.comparing methode gebruikt een methode die de eigenschap berekent die zal worden gebruikt voor het vergelijken van items, en retourneert een overeenkomst Comparator voorbeeld:

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

U kunt de Java 8-functionaliteit diepgaand verkennen in onze Java 8 Comparator.comparing-gids.

5. Comparator vs Vergelijkbaar

De Vergelijkbaar interface is een goede keuze wanneer deze wordt gebruikt voor het definiëren van de standaardvolgorde of, met andere woorden, als dit de belangrijkste manier is om objecten te vergelijken.

Vervolgens moeten we ons afvragen waarom een Comparator als we dat al hebben gedaan Vergelijkbaar?

Er zijn verschillende redenen waarom:

  • Soms kunnen we de broncode van de klasse waarvan we de objecten willen sorteren niet wijzigen, waardoor we er gebruik van kunnen maken Vergelijkbaar onmogelijk
  • Gebruik makend van Vergelijkers stelt ons in staat om geen extra code toe te voegen aan onze domeinklassen
  • We kunnen meerdere verschillende vergelijkingsstrategieën definiëren die niet mogelijk zijn bij gebruik Vergelijkbaar

6. Het vermijden van de aftrektruc

In de loop van deze tutorial hebben we de Integer.compare () methode om twee gehele getallen te vergelijken. Je zou kunnen zeggen dat we in plaats daarvan deze slimme oneliner moeten gebruiken:

Comparator comparator = (p1, p2) -> p1.getRanking () - p2.getRanking ();

Hoewel het veel beknopter is in vergelijking met andere oplossingen, kan het het slachtoffer zijn van integer overflows in Java:

Player player1 = nieuwe Player (59, "John", Integer.MAX_VALUE); Player player2 = nieuwe speler (67, "Roger", -1); Lijst met spelers = Arrays.asList (speler1, speler2); players.sort (vergelijker);

Omdat -1 veel minder is dan de Geheel getal.MAX_VALUE, "Roger" moet voor de "John" komen in de gesorteerde verzameling. Echter, als gevolg van integer overflow, de "Geheel getal.MAX_VALUE - (-1)" zal kleiner zijn dan nul. Dus, gebaseerd op de Comparator / vergelijkbaar contract, het Geheel getal.MAX_VALUE is kleiner dan -1, wat duidelijk onjuist is.

Vandaar dat, ondanks wat we hadden verwacht, "John" voor de "Roger" komt in de gesorteerde verzameling:

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

7. Conclusie

In deze tutorial hebben we de Vergelijkbaar en Comparator interfaces en bespraken de verschillen daartussen.

Om meer geavanceerde onderwerpen van sorteren te begrijpen, bekijk onze andere artikelen zoals Java 8 Comparator, Java 8 Vergelijking met Lambdas.

En, zoals gewoonlijk, is de broncode te vinden op GitHub.


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