Komparátor a porovnateľný v Jave

1. Úvod

Porovnania v Jave sú celkom jednoduché - pokiaľ nie sú.

Pri práci s vlastnými typmi alebo pri pokuse o porovnanie objektov, ktoré nie sú priamo porovnateľné, musíme využiť porovnávaciu stratégiu. Jeden môžeme postaviť jednoducho, ale s využitím Komparátor alebo Porovnateľné rozhrania.

2. Príprava príkladu

Zoberme si príklad futbalového tímu - kde chceme zoradiť hráčov podľa ich poradia.

Začneme vytvorením jednoduchého Prehrávač trieda:

public class Player {private int hodnotenie; súkromné ​​meno reťazca; súkromný int vek; // konštruktor, getri, nastavovatelia}

Ďalej vytvoríme a PlayerSorter triedy, aby sme vytvorili našu zbierku a pokúsili sa ju triediť pomocou Zbierky.triediť:

public static void main (String [] args) {List footballTeam = new ArrayList (); Hráč player1 = nový Hráč (59, „John“, 20); Hráč player2 = nový Hráč (67, „Roger“, 22); Hráč player3 = nový hráč (45, „Steven“, 24); footballTeam.add (player1); footballTeam.add (player2); footballTeam.add (player3); System.out.println ("Pred triedením:" + footballTeam); Zbierka.sort (footballTeam); System.out.println ("Po zoradení:" + footballTeam); } 

Podľa očakávania to má za následok chybu v čase kompilácie:

Zoradenie metódy (Zoznam) v type Zbierky nie je použiteľné pre argumenty (ArrayList)

Poďme pochopiť, čo sme tu urobili zle.

3. Porovnateľné

Ako už názov napovedá, Porovnateľné je rozhranie definujúce stratégiu porovnávania objektu s inými objektmi rovnakého typu. Toto sa nazýva „prirodzené usporiadanie“ triedy.

Preto, aby sme mohli triediť - musíme si definovať svoje Prehrávač objekt porovnateľný vykonaním Porovnateľné rozhranie:

verejná trieda Prehrávač implementuje porovnateľné {// rovnaké ako predtým @Override public int compareTo (Player otherPlayer) {return Integer.compare (getRanking (), otherPlayer.getRanking ()); }} 

O poradí triedenia rozhoduje návratová hodnota súboru porovnať s()metóda. The Integer.compare (x, y) vráti -1, ak X je menej než r, vráti 0, ak sú rovnaké, a vráti 1 inak.

Metóda vracia číslo označujúce, či je porovnávaný objekt menší ako, rovný alebo väčší ako objekt odovzdávaný ako argument.

Nakoniec, keď spustíme naše PlayerSorter teraz môžeme vidieť naše Hráči zoradené podľa poradia:

Pred triedením: [John, Roger, Steven] Po triedení: [Steven, John, Roger]

Teraz, keď máme jasné pochopenie prirodzeného usporiadania s Porovnateľné, Pozrime sa ako môžeme pružnejšie využiť iné typy objednávania než priamo implementovať rozhranie.

4. Komparátor

The Komparátor rozhranie definuje a porovnaj (arg1, arg2) metóda s dvoma argumentmi, ktoré reprezentujú porovnávané objekty a fungujú podobne ako Comparable.compareTo () metóda.

4.1. Tvorenie Komparátory

Ak chcete vytvoriť Komparátor, musíme implementovať Komparátor rozhranie.

V našom prvom príklade vytvoríme a Komparátor používať poradie atribút Prehrávač zoradiť hráčov:

verejná trieda PlayerRankingComparator implementuje komparátor {@Override public int compare (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getRanking (), secondPlayer.getRanking ()); }}

Podobne môžeme vytvoriť a Komparátor používať Vek atribút Prehrávač zoradiť hráčov:

verejná trieda PlayerAgeComparator implementuje komparátor {@Override public int compare (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getAge (), secondPlayer.getAge ()); }}

4.2. Komparátory v akcii

Aby sme demonštrovali tento koncept, upravme náš PlayerSorter - vložením druhého argumentu do Metóda zbierok čo je vlastne inštancia Komparátor chceme použiť.

Pomocou tohto prístupu môžeme potlačiť prirodzené usporiadanie:

PlayerRankingComparator playerComparator = nový PlayerRankingComparator (); Zbierka.sort (footballTeam, playerComparator); 

Poďme teraz PlayerRankingSorter do pozri výsledok:

Pred zoradením: [John, Roger, Steven] Po zoradení podľa poradia: [Steven, John, Roger]

Ak chceme iné poradie triedenia, stačí zmeniť Komparátor používame:

PlayerAgeComparator playerComparator = nový PlayerAgeComparator (); Zbierka.sort (footballTeam, playerComparator);

Teraz, keď spustíme náš PlayerAgeSorter, môžeme vidieť iné poradie zoradenia podľa Vek:

Pred zoradením: [John, Roger, Steven] Po zoradení podľa veku: [Roger, John, Steven]

4.3. Java 8 Komparátory

Java 8 poskytuje nové spôsoby definovania Komparátory pomocou výrazov lambda a porovnanie () statická továrenská metóda.

Pozrime sa na krátky príklad toho, ako použiť výraz lambda na vytvorenie a Komparátor:

Komparátor byRanking = (Hráč hráč1, Hráč hráč2) -> Integer.compare (player1.getRanking (), player2.getRanking ());

The Comparator.comparing metóda vezme metódu výpočtu vlastnosti, ktorá sa použije na porovnanie položiek, a vráti zhodu Komparátor inštancia:

Comparator byRanking = komparátor. Porovnanie (Player :: getRanking); Comparator byAge = komparátor. Porovnanie (Player :: getAge);

Funkcie Java 8 môžete podrobne preskúmať v našom sprievodcovi porovnávaním Java 8 Comparator.com.

5. Komparátor vs Porovnateľné

The Porovnateľné rozhranie je dobrou voľbou, keď sa používa na definovanie predvoleného poradia alebo inými slovami, ak je to hlavný spôsob porovnávania objektov.

Potom si musíme položiť otázku, prečo používať a Komparátor ak už máme Porovnateľné?

Existuje niekoľko dôvodov, prečo:

  • Niekedy nemôžeme upraviť zdrojový kód triedy, ktorej objekty chceme zoradiť, a tak to využiť Porovnateľné nemožné
  • Použitím Komparátory umožňuje vyhnúť sa pridávaniu ďalších kódov do našich doménových tried
  • Môžeme definovať niekoľko rôznych porovnávacích stratégií, čo pri použití nie je možné Porovnateľné

6. Vyhýbanie sa triku odčítania

V priebehu tohto tutoriálu sme použili Integer.compare () metóda na porovnanie dvoch celých čísel. Niekto by mohol namietať, že by sme mali namiesto toho použiť túto šikovnú jednoradovú linku:

Komparátor komparátor = (p1, p2) -> p1.getRanking () - p2.getRanking ();

Aj keď je to v porovnaní s inými riešeniami oveľa stručnejšie, môže sa stať obeťou celotelového pretečenia v Jave:

Hráč player1 = nový Hráč (59, „John“, Integer.MAX_VALUE); Hráč player2 = nový Hráč (67, „Roger“, -1); Zoznam hráčov = Arrays.asList (player1, player2); players.sort (komparátor);

Pretože -1 je oveľa menej ako Celé číslo.MAX_VALUE„Roger“ by mal prísť pred „Johna“ v triedenej zbierke. Kvôli celotelovému pretečeniu však „Integer.MAX_VALUE - (-1)“ bude menej ako nula. Takže na základe Porovnávač / Porovnateľný zmluva, Celé číslo.MAX_VALUE je menej ako -1, čo je zjavne nesprávne.

Preto aj napriek tomu, čo sme očakávali, prichádza „John“ pred „Rogera“ v triedenej zbierke:

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

7. Záver

V tomto návode sme preskúmali Porovnateľné a Komparátor rozhrania a diskutovali o rozdieloch medzi nimi.

Ak chcete porozumieť pokročilejším témam triedenia, pozrite si naše ďalšie články, ako sú Java 8 Comparator, Java 8 Comparison s Lambdas.

A ako obvykle, zdrojový kód nájdete na GitHub.


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