Ohjelmointi

Lajittelu Comparable- ja Comparator-sovellusten kanssa Java-sovelluksessa

Ohjelmoijien on usein lajiteltava elementit tietokannasta kokoelmaan, taulukkoihin tai karttoihin. Java: ssa voimme toteuttaa minkä tahansa haluamamme lajittelualgoritmin mihin tahansa tyyppiin. Käyttämällä Vertailukelpoinen käyttöliittymä ja vertaa() menetelmällä voimme lajitella aakkosjärjestyksessä, Merkkijono pituus, käänteinen aakkosjärjestys tai numerot. Vertailija käyttöliittymän avulla voimme tehdä saman, mutta joustavammin.

Mitä haluamme tehdä, meidän on vain tiedettävä, kuinka toteuttaa oikea lajittelulogiikka annetulle käyttöliittymälle ja tyypille.

Hanki lähdekoodi

Hanki koodi tälle Java Challengerille. Voit suorittaa omia testejä samalla kun noudatat esimerkkejä.

Java-luettelon lajittelu mukautetulla objektilla

Esimerkissä käytämme samaa POJO: ta, jota olemme tähän mennessä käyttäneet muille Java-haastajille. Tässä ensimmäisessä esimerkissä toteutamme Vertailukelpoisen käyttöliittymän Simpson luokassa käyttäen Simpson yleisessä tyypissä:

 luokan Simpson toteuttaa Vertailukelpoinen {String name; Simpson (merkkijono) {this.name = nimi; } @Override public int CompareTo (Simpson simpson) {palauta this.name.compareTo (simpson.name); }} public class SimpsonSorting {public static void main (String ... sortingWithList) {Lista simpsonit = uusi ArrayList (); simpsons.add (uusi SimpsonCharacter ("Homer")); simpsons.add (uusi SimpsonCharacter ("Marge")); simpsons.add (uusi SimpsonCharacter ("Bart")); simpsons.add (uusi SimpsonCharacter ("Lisa")); Collections. Lajittelu (simpsonit); simpsons.stream (). map (s -> s.name) .forEach (System.out :: print); Kokoelmat.käänteinen (simpsonit); simpsons.stream (). forEach (System.out :: print); }} 

Huomaa, että olemme ohittaneet CompareTo () -menetelmän ja siirtäneet toisen Simpson esine. Olemme myös ohittaneet toString () menetelmällä, vain jotta esimerkki olisi helpompi lukea.

merkkijono menetelmä näyttää kaikki objektin tiedot. Kun tulostamme objektin, tulosteet ovat mitä tahansa toString ().

CompareTo () -menetelmä

vertaa() menetelmä vertaa tiettyä objektia tai nykyistä esiintymää määritettyyn objektiin objektien järjestyksen määrittämiseksi. Tässä on nopea kuvaus miten vertaa() toimii:

Jos vertailu palaa

Sitten ...

  >= 1

  this.name> simpson.name

  0

  this.name == simpson.name

  <= -1

  this.name <simpson.name

Voimme käyttää vain luokkia, jotka ovat verrattavissa järjestellä() menetelmä. Jos yritämme läpäistä a Simpson jota ei toteuteta Vertailukelpoinen, saamme kokoamisvirheen.

järjestellä() menetelmä käyttää polymorfismia ohittamalla minkä tahansa objektin, joka on Vertailukelpoinen. Objektit lajitellaan sitten odotetulla tavalla.

Edellisen koodin lähtö olisi:

 Bart Homer Lisa Marge 

Jos haluaisimme muuttaa järjestystä, voisimme vaihtaa järjestellä() a käänteinen(); alkaen:

 Collections. Lajittelu (simpsonit); 

vastaanottajalle:

 Kokoelmat.käänteinen (simpsonit); 

Käyttöönotto käänteinen() menetelmä muuttaisi edellisen tuotoksen muotoon:

 Marge Lisa Homer Bart 

Java-taulukon lajittelu

Java: ssa voimme lajitella taulukon haluamallamme tavalla, kunhan se toteuttaa Vertailukelpoinen käyttöliittymä. Tässä on esimerkki:

 public class ArraySorting {public static void main (String ... moeTavern) {int [] moesPints ​​= new int [] {9, 8, 7, 6, 1}; Taulukot.lajittelu (moesPints); Taulukot.stream (moesPints) .forEach (System.out :: print); Simpson [] simpsons = uusi Simpson [] {uusi Simpson ("Lisa"), uusi Simpson ("Homer")}; Taulukot.lajittelu (simpsonit); Arrays.stream (simpsons) .forEach (System.out :: println); }} 

Ensimmäisessä järjestellä() kutsu, taulukko on lajiteltu:

 1 6 7 8 9 

Toisessa järjestellä() kutsu, se on lajiteltu:

 Homer Lisa 

Muista, että mukautettujen objektien on toteutettava Vertailukelpoinen lajiteltavaksi, jopa matriisina.

Voinko lajitella objekteja ilman vertailukelpoista?

Jos Simpson-objektia ei toteutettu Vertailukelpoinen, ClassCastException heitetään. Jos suoritat tämän testinä, näet jotain seuraavanlaista:

 Virhe: (16, 20) java: Lajittelu- (java.util.List) -menetelmälle ei löytynyt sopivaa menetelmää com.javaworld.javachallengers.sortingcomparable. ) T (todelliset ja muodolliset argumenttiluettelot eroavat toisistaan) 

Tämä loki voi olla hämmentävä, mutta älä huoli. Pidä vain mielessä, että a ClassCastException heitetään jokaiselle lajitellulle objektille, joka ei toteuta Vertailukelpoinen käyttöliittymä.

Kartan lajittelu TreeMapilla

Java-sovellusliittymä sisältää monia luokkia, jotka auttavat lajittelussa, mukaan lukien TreeMap. Seuraavassa esimerkissä käytämme PuuKartta lajitella avaimet a Kartta.

 public class TreeMapExample {public static void main (String ... barney) {Map simpsonsCharacters = new TreeMap (); simpsonsCharacters.put (uusi SimpsonCharacter ("Moe"), "haulikko"); simpsonsCharacters.put (uusi SimpsonCharacter ("Lenny"), "Carl"); simpsonsCharacters.put (uusi SimpsonCharacter ("Homer"), "televisio"); simpsonsCharacters.put (uusi SimpsonCharacter ("Barney"), "olut"); System.out.println (simpsonsCharacters); }} 

PuuKartta käyttää vertaa() - menetelmä, jonka Vertailukelpoinen käyttöliittymä. Jokainen tuloksena olevan elementin Kartta on lajiteltu avaimensa mukaan. Tässä tapauksessa tuotos olisi:

 Barney = olut, Homer = televisio, Lenny = Carl, Moe = haulikko 

Muista kuitenkin: jos objekti ei toteudu Vertailukelpoinen, a ClassCastException heitetään.

Sarjan lajittelu TreeSetin avulla

Aseta käyttöliittymä on vastuussa yksilöllisten arvojen tallentamisesta, mutta kun käytämme TreeSet-toteutusta, lisätyt elementit lajitellaan automaattisesti, kun ne lisätään:

 public class TreeSetExample {public static void main (String ... barney) {Set simpsonsCharacters = new TreeSet (); simpsonsCharacters.add (uusi SimpsonCharacter ("Moe")); simpsonsCharacters.add (uusi SimpsonCharacter ("Lenny")); simpsonsCharacters.add (uusi SimpsonCharacter ("Homer")); simpsonsCharacters.add (uusi SimpsonCharacter ("Barney")); System.out.println (simpsonsCharacters); }} 

Tämän koodin lähtö on:

 Barney, Homer, Lenny, Moe 

Jälleen, jos käytämme kohdetta, joka ei ole Vertailukelpoinen, a ClassCastException heitetään.

Lajittelu vertailijan kanssa

Entä jos emme halua käyttää samaa vertaa() menetelmä POJO-luokasta? Voisimmeko ohittaa Vertailukelpoinen menetelmä käyttää erilaista logiikkaa? Alla on esimerkki:

 public class BadExampleOfComparable {public static void main (String ... args) {Luettelomerkit = uusi ArrayList (); SimpsonCharacter homer = uusi SimpsonCharacter ("Homer") {@Override public int CompareTo (SimpsonCharacter simpson) {return this.name.length () - (simpson.name.length ()); }}; SimpsonCharacter moe = uusi SimpsonCharacter ("Moe") {@Override public int CompareTo (SimpsonCharacter simpson) {return this.name.length () - (simpson.name.length ()); }}; merkit. add (homer); merkit. lisää (moe); Collections. Lajittelu (merkit); System.out.println (merkkiä); }} 

Kuten näette, tämä koodi on monimutkainen ja sisältää paljon toistoja. Meidän piti ohittaa vertaa() kahdesti samaa logiikkaa varten. Jos elementtejä olisi enemmän, meidän olisi toistettava jokaisen objektin logiikka.

Onneksi meillä on Comparator-käyttöliittymä, jonka avulla voimme irrottaa vertaa() logiikka Java-luokista. Harkitse samaa esimerkkiä, joka on kirjoitettu uudestaan Vertailija:

 public class GoodExampleOfComparator {public static void main (String ... args) {Luettelomerkit = uusi ArrayList (); SimpsonCharacter homer = uusi SimpsonCharacter ("Homer"); SimpsonCharacter moe = uusi SimpsonCharacter ("Moe"); merkit. add (homer); merkit. lisää (moe); Collections.sort (merkit, (Comparator. VertaaInt (merkki1 -> merkki1.nimi.pituus ()) .thenComparingInt (merkki2 -> merkki2.nimi.pituus ()))); System.out.println (merkkiä); }} 

Nämä esimerkit osoittavat tärkeimmän eron Vertailukelpoinen ja Vertailija.

Käyttää Vertailukelpoinen kun kohteellesi on yksi, oletusarvoinen vertailu. Käyttää Vertailijakun sinun täytyy kiertää olemassa olevaa vertaa()tai kun sinun on käytettävä tiettyä logiikkaa joustavammin. Vertailija irrottaa lajittelulogiikan objektistasi ja sisältää vertaa() logiikka sisällä järjestellä() menetelmä.

Comparatorin käyttö nimettömän sisäisen luokan kanssa

Tässä seuraavassa esimerkissä vertaamme esineiden arvoa nimettömän sisäisen luokan kanssa. An tuntematon sisempi luokka, tässä tapauksessa on mikä tahansa luokka, joka toteuttaa Vertailija. Sen käyttö tarkoittaa, että emme ole sitoutuneita nimeämään luokkaa ilmentämään käyttöliittymää; sen sijaan toteutamme vertaa() menetelmä tuntemattoman sisäisen luokan sisällä.

 public class MarvelComparator {public static void main (String ... Comparator) {Lista marvelHeroes = new ArrayList (); marvelHeroes.add ("Hämähäkkimies"); marvelHeroes.add ("Ahma"); marvelHeroes.add ("Xavier"); marvelHeroes.add ("Kyklooppi"); Collections.sort (marvelHeroes, new Comparator () {@Override public int vertaile (String hero1, String hero2) {return hero1.compareTo (hero2);}}); Collections.sort (marvelHeroes, (m1, m2) -> m1.compareTo (m2)); Collections.sort (marvelHeroes, Comparator.naturalOrder ()); marvelHeroes.forEach (System.out :: print); }} 

Lisätietoja sisemmistä luokista

An tuntematon sisempi luokka on yksinkertaisesti mikä tahansa luokka, jonka nimellä ei ole väliä ja joka toteuttaa ilmoitettavan käyttöliittymän. Joten esimerkissä uusi Vertailija on itse asiassa luokan luokse, jolla ei ole nimeä, mikä toteuttaa menetelmän haluamallamme logiikalla.

Comparatorin käyttö lambda-lausekkeiden kanssa

Anonyymit sisäiset luokat ovat yksityiskohtaisia, mikä voi aiheuttaa ongelmia koodissamme. vuonna Vertailija käyttöliittymän avulla voimme käyttää lambda-lausekkeita yksinkertaistamaan ja helpottamaan koodin lukemista. Voisimme esimerkiksi muuttaa tätä:

 Collections.sort (ihme, uusi Comparator () {@Override public int vertaile (String hero1, String hero2) {return hero1.compareTo (hero2);}}); 

tähän:

 Kokoelmat. Lajittelu (ihme, (m1, m2) -> m1.vertaTo (m2)); 

Vähemmän koodia ja sama tulos!

Tämän koodin lähtö olisi:

 Kyklooppi SpiderMan Wolverine Xavier 

Voimme tehdä koodista vielä yksinkertaisemman muuttamalla tätä:

 Kokoelmat. Lajittelu (ihme, (m1, m2) -> m1.vertaTo (m2)); 

tähän:

 Collections.sort (ihme, Comparator.naturalOrder ()); 

Lambda-lausekkeet Java-kielellä

Lue lisää lambda-lausekkeista ja muista Java-toiminnallisista ohjelmointitekniikoista.

Ovatko ydin Java-luokat vertailukelpoisia?

Monet Java-ydinluokat ja -objektit toteuttavat Vertailukelpoinen käyttöliittymä, mikä tarkoittaa, että meidän ei tarvitse ottaa käyttöön vertaa() näiden luokkien logiikka. Tässä on muutama tuttu esimerkki:

Merkkijono

 public final class String toteuttaa java.io.Serializable, Comparable, CharSequence {... 

Kokonaisluku

 julkinen loppuluokka Kokonaisluku laajentaa Numerototeutuksia Vertailukelpoinen {… 

Kaksinkertainen

 julkinen finaaliluokka Tuplalaajennukset Numerotarvikkeet Vertailukelpoinen {... 

On monia muita. Kehotan teitä tutkimaan Java-ydinluokkia oppimaan niiden tärkeät mallit ja käsitteet.

Vastaa Vertailukelpoisen käyttöliittymän haasteeseen!

Testaa oppimasi selvittämällä seuraavan koodin lähtö. Muista, että opit parhaiten, jos ratkaiset tämän haasteen itse vain tutkimalla sitä. Kun olet saanut vastauksen, voit tarkistaa vastauksen alla. Voit myös suorittaa omat testisi käsitteiden täydelliseksi hyödyntämiseksi.

 public class SortComparableChallenge {public static void main (String ... doYourBest) {Set set = new TreeSet (); set.add (uusi Simpson ("Homer")); set.add (uusi Simpson ("Marge")); set.add (uusi Simpson ("Lisa")); set.add (uusi Simpson ("Bart")); set.add (uusi Simpson ("Maggie")); List list = new ArrayList (); list.addAll (sarja); Kokoelmat.käänteinen (luettelo); list.forEach (System.out :: println); } staattinen luokka Simpson toteuttaa Vertailukelpoinen {String name; julkinen Simpson (merkkijono) {this.name = nimi; } public int vertaileTo (Simpson simpson) {palauta simpson.nimi.vertaaTo (tämä.nimi); } public String toString () {palauta tämä.nimi; }}} 

Mikä on tämän koodin lähtö?

 A) Bart Homer Lisa Maggie Marge B) Maggie Bart Lisa Marge Homer C) Marge Maggie Lisa Homer Bart D) Määrittelemätön 
$config[zx-auto] not found$config[zx-overlay] not found