Komparátor és összehasonlítható Java-ban

1. Bemutatkozás

A Java-ban történő összehasonlítás meglehetősen egyszerű - amíg nem.

Ha egyéni típusokkal dolgozunk, vagy megpróbáljuk összehasonlítani azokat az objektumokat, amelyek nem közvetlenül összehasonlíthatók, használnunk kell egy összehasonlítási stratégiát. Egyszerűen felépíthetjük, de felhasználva a Összehasonlító vagy Hasonló interfészek.

2. A példa beállítása

Vegyünk egy példát egy futballcsapatra - ahol a játékosokat rangsor szerint akarjuk felsorakoztatni.

Kezdjük egy egyszerű létrehozásával Játékos osztály:

nyilvános osztály Player {private int ranking; privát karakterlánc neve; privát int kor; // kivitelező, getters, setters}

Ezután hozzunk létre egy PlayerSorter osztály létrehozni a gyűjteményünket, és megkísérelni rendezni a felhasználásával Gyűjtemények.rendezés:

public static void main (String [] args) {List footballTeam = new ArrayList (); Player player1 = új játékos (59, "John", 20); Player2 = új játékos (67, "Roger", 22); Player3 = új játékos (45, "Steven", 24); footballTeam.add (player1); footballTeam.add (player2); footballTeam.add (player3); System.out.println ("Rendezés előtt:" + footballTeam); Gyűjtemények.rendezés (footballTeam); System.out.println ("Rendezés után:" + footballTeam); } 

A várakozásoknak megfelelően ez fordítási időbeli hibát eredményez:

A Gyűjtemények típusú sort (Lista) a argumentumokra nem lehet alkalmazni (ArrayList)

Értsük meg, mit tettünk itt rosszul.

3. Hasonló

Ahogy a neve is sugallja, Hasonló egy interfész, amely meghatározza az objektum más azonos típusú objektumokkal való összehasonlításának stratégiáját. Ezt hívják az osztály „természetes rendezésének”.

Ennek megfelelően, a rendezéshez - meg kell határoznunk a sajátunkat Játékos objektum, mint összehasonlítható a Hasonló felület:

public class Player megvalósítja a Comparable {// -ot, mint korábban @Orride public int CompareTo (Player otherPlayer) {return Integer.compare (getRanking (), otherPlayer.getRanking ()); }} 

A rendezési sorrendet a. Visszatérési értéke határozza meg összehasonlítani()módszer. A Egész. Összehasonlítás (x, y) -1-et ad vissza x kevesebb mint y, 0-t ad vissza, ha egyenlőek, és 1-et ad vissza.

A módszer számot ad vissza, jelezve, hogy az összehasonlítandó objektum kisebb-e, egyenlő vagy nagyobb-e, mint az argumentumként átadott objektum.

Végül, amikor futunk PlayerSorter most láthatjuk a mi Játékosok rangsor szerint rendezve:

Rendezés előtt: [John, Roger, Steven] Rendezés után: [Steven, John, Roger]

Most, hogy világos megértésünk van a természetes rendezésről Hasonló, lássuk hogyan használhatunk más típusú megrendeléseket rugalmasabban mint egy interfész közvetlen megvalósítása.

4. Összehasonlító

A Összehasonlító interfész meghatározza a összehasonlít (arg1, arg2) módszer két argumentummal, amelyek összehasonlított objektumokat képviselnek és hasonlóan működnek, mint a Comparable.compareTo () módszer.

4.1. Teremtés Összehasonlítók

A Összehasonlító, végre kell hajtanunk a Összehasonlító felület.

Első példánkban létrehozunk egy Összehasonlító használni a rangsor attribútuma Játékos a játékosok rendezéséhez:

public class PlayerRankingComparator implementálja a Comparator {@Orride public int összehasonlítás (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getRanking (), secondPlayer.getRanking ()); }}

Hasonlóképpen létrehozhatunk egy Összehasonlító használni a kor attribútuma Játékos a játékosok rendezéséhez:

public class PlayerAgeComparator implementálja a Comparator {@Orride public int Compare (Player firstPlayer, Player secondPlayer) {return Integer.compare (firstPlayer.getAge (), secondPlayer.getAge ()); }}

4.2. Összehasonlítók akcióban

A koncepció bemutatásához módosítsuk PlayerSorter egy második érv bevezetésével a Gyűjtemények.rendezési módszer ami valójában a Összehasonlító használni akarjuk.

Ezzel a megközelítéssel felülírhatjuk a természetes sorrendet:

PlayerRankingComparator playerComparator = új PlayerRankingComparator (); Collections.sort (footballTeam, playerComparator); 

Most futtassuk PlayerRankingSorter to lásd az eredményt:

Rendezés előtt: [John, Roger, Steven] Rendezés rangsorolás után: [Steven, John, Roger]

Ha más rendezési sorrendet akarunk, akkor csak a Összehasonlító használjuk:

PlayerAgeComparator playerComparator = új PlayerAgeComparator (); Collections.sort (footballTeam, playerComparator);

Most, amikor futunk PlayerAgeSorter, láthatunk egy másik rendezési sorrendet kor:

Rendezés előtt: [John, Roger, Steven] Kor szerinti rendezés után: [Roger, John, Steven]

4.3. Java 8 Összehasonlítók

A Java 8 új módszereket kínál a meghatározásra Összehasonlítók lambda kifejezések és a összehasonlítás () statikus gyári módszer.

Lássunk egy gyors példát arra, hogyan használhatunk lambda kifejezést a Összehasonlító:

Comparator byRanking = (Player Player1, Player Player2) -> Egész szám.összehasonlítás (player1.getRanking (), player2.getRanking ());

A Összehasonlító.összehasonlítás A metódus elvégzi az elemek összehasonlításához használt tulajdonság kiszámításának módszerét, és egyezést ad vissza Összehasonlító példa:

Comparator byRanking = Összehasonlító .comparing (Player :: getRanking); Comparator byAge = Összehasonlító .összehasonlítás (Player :: getAge);

A Java 8 funkcionalitását a Java 8 Comparator.comparing útmutatóban találja meg alaposan.

5. Összehasonlító vs. Hasonló

A Hasonló Az interfész jó választás az alapértelmezett sorrend meghatározásához vagy más szavakkal, ha ez az objektumok összehasonlításának fő módja.

Ezután fel kell tennünk magunknak a kérdést, miért használjuk az a Összehasonlító ha már megvan Hasonló?

Ennek számos oka van:

  • Néha nem tudjuk módosítani annak az osztálynak a forráskódját, amelynek objektumait rendezni szeretnénk, így kihasználva Hasonló lehetetlen
  • Használata Összehasonlítók lehetővé teszi számunkra, hogy ne adjunk további kódot a domain osztályainkhoz
  • Több különböző összehasonlítási stratégiát határozhatunk meg, amelyek használata nem lehetséges Hasonló

6. Kerülje el a kivonási trükköt

A bemutató során a Integer.compare () módszer két egész szám összehasonlítására. Azt állíthatnánk, hogy ehelyett ezt az okos egybélést kell használnunk:

Összehasonlító összehasonlító = (p1, p2) -> p1.getRanking () - p2.getRanking ();

Bár sokkal tömörebb a többi megoldáshoz képest, a Java egész számának túlcsordulásának áldozata lehet:

Player player1 = új játékos (59, "John", egész szám.MAX_VALUE); Player2 = új játékos (67, "Roger", -1); Játékosok listája = Arrays.asList (player1, player2); játékosok.rendezés (összehasonlító);

Mivel -1 sokkal kisebb, mint a Egész.MAX_VALUE, „Roger” -nek a válogatott gyűjtemény „John” elé kell kerülnie. Az egész szám túlcsordulása miatt azonban a „Egész.MAX_VALUE - (-1)” kevesebb lesz, mint nulla. Tehát a Összehasonlító / összehasonlítható szerződés, az Egész.MAX_VALUE kisebb mint -1, ami nyilvánvalóan helytelen.

Ezért, annak ellenére, amit vártunk, „John” a válogatott gyűjtemény „Roger” elé kerül:

assertEquals ("John", játékosok.get (0) .getName ()); assertEquals ("Roger", játékosok.get (1) .getName ());

7. Következtetés

Ebben az oktatóanyagban a Hasonló és Összehasonlító interfészeket, és megvitatták a közöttük lévő különbségeket.

A válogatás fejlettebb témáinak megértéséhez olvassa el a többi cikkünket, például a Java 8 Comparator, a Java 8 Comparison with Lambdas.

És, mint általában, a forráskód megtalálható a GitHubon.