Programiranje

Razvrščanje s primerljivimi in primerjalnimi napravami v Javi

Programerji morajo pogosto razvrstiti elemente iz baze podatkov v zbirko, matriko ali zemljevid. V Javi lahko implementiramo poljuben algoritem za razvrščanje s katero koli vrsto. Uporabljati Primerljivo vmesnik in compareTo () lahko razvrstimo po abecednem vrstnem redu, Vrvica dolžina, obratni abecedni vrstni red ali številke. The Primerjalnik vmesnik nam omogoča, da naredimo enako, vendar na bolj prilagodljiv način.

Karkoli želimo storiti, le vedeti moramo, kako implementirati pravilno logiko razvrščanja za dani vmesnik in vrsto.

Pridobite izvorno kodo

Pridobite kodo za ta Java Challenger. Med sledenjem primerom lahko izvajate lastne teste.

Razvrščanje seznama Java s predmetom po meri

Za naš primer bomo uporabili isti POJO, ki smo ga doslej uporabljali za druge Java Challengerje. V tem prvem primeru izvedemo primerljiv vmesnik v Simpson razred, z uporabo Simpson v generičnem tipu:

 razred Simpson izvaja Primerljivo {String name; Simpson (ime niza) {this.name = ime; } @Override public int compareTo (Simpson simpson) {return this.name.compareTo (simpson.name); }} javni razred SimpsonSorting {public static void main (String ... sortingWithList) {List simpsons = new ArrayList (); simpsons.add (novo SimpsonCharacter ("Homer")); simpsons.add (novo SimpsonCharacter ("Marge")); simpsons.add (novo SimpsonCharacter ("Bart")); simpsons.add (novo SimpsonCharacter ("Lisa")); Collections.sort (simpsoni); simpsons.stream (). map (s -> s.name) .forEach (System.out :: print); Collections.reverse (simpsoni); simpsons.stream (). forEach (System.out :: print); }} 

Upoštevajte, da smo preglasili metodo compareTo () in poslali drugo Simpson predmet. Prav tako smo preglasili toString () , da bi primer lažje prebrali.

The toString metoda prikazuje vse informacije iz predmeta. Ko natisnemo predmet, bo rezultat, kar je bilo implementirano v toString ().

Metoda compareTo ()

The compareTo () metoda primerja dani predmet ali trenutni primerek z določenim predmetom, da določi vrstni red predmetov. Tukaj je hiter pogled, kako compareTo () dela:

Če se primerjava vrne

Potem ...

  >= 1

  this.name> simpson.name

  0

  this.name == simpson.name

  <= -1

  to.ime <simpson.name

Uporabljamo lahko le razrede, ki so primerljivi z razvrsti () metoda. Če poskušamo prenesti a Simpson ki se ne izvaja Primerljivo, bomo prejeli napako pri sestavljanju.

The razvrsti () metoda uporablja polimorfizem s prenašanjem katerega koli predmeta, ki je Primerljivo. Predmeti bodo nato razvrščeni po pričakovanjih.

Rezultat prejšnje kode bi bil:

 Bart Homer Lisa Marge 

Če bi želeli obrniti vrstni red, bi ga lahko zamenjali razvrsti () za vzvratno (); od:

 Collections.sort (simpsoni); 

do:

 Collections.reverse (simpsoni); 

Uvajanje vzvratno () metoda bi prejšnji izhod spremenila v:

 Marge Lisa Homer Bart 

Razvrščanje polja Java

V Javi lahko vrsto razvrstimo s poljubno vrsto, če le ta izvaja Primerljivo vmesnik. Tu je primer:

 javni razred ArraySorting {javna statična void main (String ... moeTavern) {int [] moesPints ​​= new int [] {9, 8, 7, 6, 1}; Arrays.sort (moesPints); Arrays.stream (moesPints) .forEach (System.out :: print); Simpson [] simpsons = new Simpson [] {new Simpson ("Lisa"), new Simpson ("Homer")}; Arrays.sort (simpsoni); Arrays.stream (simpsons) .forEach (System.out :: println); }} 

V prvem razvrsti () priklic, je matrika razvrščena na:

 1 6 7 8 9 

V drugem razvrsti () klic, se razvrsti na:

 Homer Lisa 

Upoštevajte, da morajo biti predmeti po meri implementirani Primerljivo za razvrščanje, tudi kot matriko.

Ali lahko razvrstim predmete brez primerljivega?

Če se Simpsonov predmet ni izvajal Primerljivo, vržen bi bil ClassCastException. Če zaženete to kot preizkus, boste videli nekaj takega:

 Napaka: (16, 20) java: za metodo razvrščanja (java.util.List) ni najdena ustrezna metoda java.util.Collections.sort (java.util.List) ni uporabna (sklepna spremenljivka T ima nezdružljive omejitve glede enakosti: com.javaworld.javachallengers.sortingcomparable.Simpson spodnje meje: java.lang.Comparable) metoda java.util.Collections.sort (java.util.List, java.util.Comparator) ni uporabna (ni mogoče določiti spremenljivk tipa (s) ) T (dejanski in formalni seznami argumentov se razlikujejo po dolžini)) 

Ta dnevnik je morda zmeden, vendar ne skrbite. Ne pozabite, da a ClassCastException bo vržen za vsak razvrščen predmet, ki ne izvaja datoteke Primerljivo vmesnik.

Razvrščanje zemljevida z TreeMapom

Java API vključuje številne razrede za pomoč pri razvrščanju, vključno z TreeMap. V spodnjem primeru uporabljamo TreeMap za razvrščanje tipk v Zemljevid.

 javni razred TreeMapExample {public static void main (String ... barney) {Map simpsonsCharacters = new TreeMap (); simpsonsCharacters.put (novo SimpsonCharacter ("Moe"), "puška"); simpsonsCharacters.put (novo SimpsonCharacter ("Lenny"), "Carl"); simpsonsCharacters.put (novo SimpsonCharacter ("Homer"), "televizija"); simpsonsCharacters.put (novo SimpsonCharacter ("Barney"), "pivo"); System.out.println (simpsonsCharacters); }} 

TreeMap uporablja compareTo () metoda, ki jo izvaja Primerljivo vmesnik. Vsak element v nastalem Zemljevid je razvrščeno po ključu. V tem primeru bi bil rezultat:

 Barney = pivo, Homer = televizija, Lenny = Carl, Moe = puška 

Vendar ne pozabite: če se objekt ne izvede Primerljivo, a ClassCastException bo vržen.

Razvrščanje niza z TreeSet

The Nastavite vmesnik je odgovoren za shranjevanje edinstvenih vrednosti, toda ko uporabimo izvedbo TreeSet, bodo vstavljeni elementi samodejno razvrščeni, ko jih dodamo:

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

Rezultat te kode je:

 Barney, Homer, Lenny, Moe 

Še enkrat, če uporabimo objekt, ki ni Primerljivo, a ClassCastException bo vržen.

Razvrščanje s primerjalnikom

Kaj pa če ne bi želeli uporabiti istega compareTo () metoda iz razreda POJO? Lahko preglasimo Primerljivo metoda za uporabo drugačne logike? Spodaj je primer:

 javni razred BadExampleOfComparable {javna statična void main (String ... args) {Znaki na seznamu = new ArrayList (); SimpsonCharacter homer = novo SimpsonCharacter ("Homer") {@ Preveri javni int compareTo (SimpsonCharacter simpson) {return this.name.length () - (simpson.name.length ()); }}; SimpsonCharacter moe = novo SimpsonCharacter ("Moe") {@ Preveri javni int compareTo (SimpsonCharacter simpson) {return this.name.length () - (simpson.name.length ()); }}; znaki.add (homer); characters.add (moe); Collections.sort (znaki); System.out.println (znaki); }} 

Kot lahko vidite, je ta koda zapletena in vključuje veliko ponovitev. Morali smo preglasiti compareTo () dvakrat za isto logiko. Če bi bilo elementov več, bi morali ponoviti logiko za vsak predmet.

Na srečo imamo primerjalni vmesnik, ki nam omogoča, da ločimo compareTo () logika iz razredov Java. Razmislite o istem zgornjem primeru, ki ste ga znova napisali z uporabo Primerjalnik:

 javni razred GoodExampleOfComparator {public static void main (String ... args) {Znaki seznama = new ArrayList (); SimpsonCharacter homer = nov SimpsonCharacter ("Homer"); SimpsonCharacter moe = novo SimpsonCharacter ("Moe"); znaki.add (homer); characters.add (moe); Collections.sort (znaki, (Primerjalnik. ComparingInt (character1 -> character1.name.length ()). ThenComparingInt (character2 -> character2.name.length ()))); System.out.println (znaki); }} 

Ti primeri kažejo glavno razliko med Primerljivo in Primerjalnik.

Uporaba Primerljivo ko obstaja ena, privzeta primerjava za vaš predmet. Uporaba Primerjalnikko morate zaobiti obstoječega compareTo ()ali kadar morate uporabiti določeno logiko na bolj prilagodljiv način. Primerjalnik loči logiko razvrščanja od vašega predmeta in vsebuje compareTo () logiko znotraj vašega razvrsti () metoda.

Uporaba primerjalnika z anonimnim notranjim razredom

V naslednjem primeru za primerjavo vrednosti predmetov uporabljamo anonimni notranji razred. An anonimni notranji razred, v tem primeru je kateri koli razred, ki izvaja Primerjalnik. Z njegovo uporabo pomeni, da nismo vezani na instanciranje imenovanega razreda, ki izvaja vmesnik; namesto tega izvajamo compareTo () metoda znotraj anonimnega notranjega razreda.

 javni razred MarvelComparator {public static void main (String ... comparator) {Seznam marvelHeroes = new ArrayList (); marvelHeroes.add ("SpiderMan"); marvelHeroes.add ("Wolverine"); marvelHeroes.add ("Xavier"); marvelHeroes.add ("Kiklop"); Collections.sort (marvelHeroes, new Comparator () {@Preveri javno int primerjavo (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); }} 

Več o notranjih tečajih

An anonimni notranji razred je preprosto vsak razred, katerega ime ni pomembno in ki izvaja vmesnik, ki ga prijavljamo. Torej v primeru novo Primerjalnik je dejansko instancija razreda, ki nima imena, ki metodo izvaja z logiko, ki jo želimo.

Uporaba primerjalnika z lambda izrazi

Anonimni notranji razredi so podrobni, kar lahko povzroči težave v naši kodi. V Primerjalnik vmesnika lahko z lambda izrazi poenostavimo in olajšamo branje kode. Lahko bi na primer to spremenili:

 Collections.sort (marvel, new Comparator () {@Preveri javno int primerjavo (String hero1, String hero2) {return hero1.compareTo (hero2);}}); 

za to:

 Collections.sort (marvel, (m1, m2) -> m1.compareTo (m2)); 

Manj kode in enak rezultat!

Rezultat te kode bi bil:

 Kiklop SpiderMan Wolverine Xavier 

Kodo bi lahko poenostavili s spremembo tega:

 Collections.sort (marvel, (m1, m2) -> m1.compareTo (m2)); 

za to:

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

Lambda izrazi v Javi

Preberite več o lambda izrazih in drugih tehnikah funkcionalnega programiranja v Javi.

So osnovni razredi Java primerljivi?

Številni osnovni razredi in predmeti Java izvajajo Primerljivo vmesnik, kar pomeni, da nam ni treba izvajati compareTo () logika za te razrede. Tu je nekaj znanih primerov:

Vrvica

 javni končni razred String implementira java.io.Serializable, Comparable, CharSequence {... 

Celo število

 javni končni razred Integer razširja Število izvedb Primerljivo {… 

Dvojno

 javni končni razred Double extends Število izvedb Primerljivo {... 

Obstaja veliko drugih. Priporočam vam, da raziščete osnovne razrede Java, da se naučite njihovih pomembnih vzorcev in konceptov.

Sprejmite izziv primerljivega vmesnika!

Preizkusite, kaj ste se naučili, tako da ugotovite, kakšen je rezultat naslednje kode. Ne pozabite, da se boste najbolje naučili, če boste ta izziv rešili sami, samo če ga boste preučili. Ko ste dobili odgovor, ga lahko preverite spodaj. Izvedete lahko tudi lastne teste, da v celoti prevzamete koncepte.

 javni razred SortComparableChallenge {public static void main (String ... doYourBest) {Set set = new TreeSet (); set.add (nov Simpson ("Homer")); set.add (nov Simpson ("Marge")); set.add (nov Simpson ("Lisa")); set.add (nov Simpson ("Bart")); set.add (nov Simpson ("Maggie")); Seznam seznamov = new ArrayList (); list.addAll (set); Collections.reverse (seznam); list.forEach (System.out :: println); } statični razred Simpson izvaja Primerljivo {String name; javni Simpson (ime niza) {this.name = ime; } public int compareTo (Simpson simpson) {return simpson.name.compareTo (this.name); } javni String toString () {return this.name; }}} 

Kateri je rezultat te kode?

 A) Bart Homer Lisa Maggie Marge B) Maggie Bart Lisa Marge Homer C) Marge Maggie Lisa Homer Bart D) Nedoločeno 
$config[zx-auto] not found$config[zx-overlay] not found