Programmerere trenger ofte å sortere elementer fra en database i en samling, matrise eller kart. I Java kan vi implementere hvilken sorteringsalgoritme vi ønsker med hvilken som helst type. Bruker Sammenlignelig
grensesnitt og sammenligne med()
metode, kan vi sortere i alfabetisk rekkefølge, String
lengde, omvendt alfabetisk rekkefølge eller tall. De Komparator
grensesnitt tillater oss å gjøre det samme, men på en mer fleksibel måte.
Uansett hva vi vil gjøre, trenger vi bare å vite hvordan vi implementerer riktig sorteringslogikk for det angitte grensesnittet og typen.
Få kildekoden
Få koden for denne Java Challenger. Du kan kjøre dine egne tester mens du følger eksemplene.
Sortere en Java-liste med et tilpasset objekt
For eksempel vil vi bruke den samme POJO som vi har brukt for andre Java-utfordrere så langt. I dette første eksemplet implementerer vi det sammenlignbare grensesnittet i Simpson
klasse, bruker Simpson
i generisk type:
klasse Simpson implementerer Comparable {String name; Simpson (strengnavn) {this.name = navn; } @Override public int compareTo (Simpson simpson) {returner this.name.compareTo (simpson.name); }} offentlig klasse SimpsonSorting {public static void main (String ... sortingWithList) {List simpsons = new ArrayList (); simpsons.add (ny SimpsonCharacter ("Homer")); simpsons.add (ny SimpsonCharacter ("Marge")); simpsons.add (ny SimpsonCharacter ("Bart")); simpsons.add (ny SimpsonCharacter ("Lisa")); Collections.sort (simpsons); simpsons.stream (). map (s -> s.name) .forEach (System.out :: print); Collections.reverse (simpsons); simpsons.stream (). forEach (System.out :: print); }}
Vær oppmerksom på at vi har overstyrt sammenligningsmetoden () og sendt inn en annen Simpson
gjenstand. Vi har også overstyrt toString ()
metode, bare for å gjøre eksemplet lettere å lese.
De toString
metoden viser all informasjon fra objektet. Når vi skriver ut objektet, vil utdataene være det som ble implementert i toString ()
.
Metoden CompareTo ()
De sammenligne med()
metoden sammenligner et gitt objekt eller den gjeldende forekomsten med et spesifisert objekt for å bestemme rekkefølgen på objekter. Her ser du raskt hvordan sammenligne med()
virker:
Hvis sammenligningen kommer tilbake | Deretter ... |
| |
| |
| |
Vi kan bare bruke klasser som er sammenlignbare med sortere()
metode. Hvis vi prøver å passere en Simpson
som ikke implementerer Sammenlignelig
, vil vi motta en kompileringsfeil.
De sortere()
metoden bruker polymorfisme ved å passere et hvilket som helst objekt Sammenlignelig
. Objekter blir deretter sortert som forventet.
Utgangen fra forrige kode ville være:
Bart Homer Lisa Marge
Hvis vi ønsket å omgjøre ordren, kunne vi bytte sortere()
for en omvendt()
; fra:
Collections.sort (simpsons);
til:
Collections.reverse (simpsons);
Implementere omvendt()
metoden vil endre forrige utgang til:
Marge Lisa Homer Bart
Sortere et Java-utvalg
I Java kan vi sortere en matrise med hvilken som helst type vi vil så lenge den implementerer Sammenlignelig
grensesnitt. Her er et eksempel:
public class ArraySorting {public static 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 = nye Simpson [] {nye Simpson ("Lisa"), nye Simpson ("Homer")}; Arrays.sort (simpsons); Arrays.stream (simpsons) .forEach (System.out :: println); }}
I det første sortere()
påkalling, er matrisen sortert til:
1 6 7 8 9
I det andre sortere()
påkallelse, den er sortert til:
Homer Lisa
Husk at tilpassede objekter må implementeres Sammenlignelig
for å bli sortert, til og med som en matrise.
Kan jeg sortere objekter uten sammenlignbare?
Hvis Simpson-objektet ikke ble implementert Sammenlignelig
, ville et ClassCastException kastes. Hvis du kjører dette som en test, vil du se noe som følgende utgang:
Feil: (16, 20) java: ingen egnet metode funnet for sort (java.util.List) -metoden java.util.Collections.sort (java.util.List) er ikke aktuelt (inferensvariabel T har uforenlige grenser for likhetsbegrensninger: com.javaworld.javachallengers.sortingcomparable.Simpson nedre grenser: java.lang.Comparable) metode java.util.Collections.sort (java.util.List, java.util.Comparator) er ikke aktuelt (kan ikke utlede typevariabel (s ) T (faktiske og formelle argumentlister er forskjellige i lengde))
Denne loggen kan være forvirrende, men ikke bekymre deg. Bare husk at en ClassCastException
vil bli kastet for ethvert sortert objekt som ikke implementerer Sammenlignelig
grensesnitt.
Sortere et kart med TreeMap
Java API inneholder mange klasser for å hjelpe til med sortering, inkludert TreeMap. I eksemplet nedenfor bruker vi TreeMap
å sortere nøkler i en Kart
.
public class TreeMapExample {public static void main (String ... barney) {Map simpsonsCharacters = new TreeMap (); simpsonsCharacters.put (ny SimpsonCharacter ("Moe"), "hagle"); simpsonsCharacters.put (ny SimpsonCharacter ("Lenny"), "Carl"); simpsonsCharacters.put (ny SimpsonCharacter ("Homer"), "TV"); simpsonsCharacters.put (ny SimpsonCharacter ("Barney"), "øl"); System.out.println (simpsonsCharacters); }}
TreeMap
bruker sammenligne med()
metoden implementert av Sammenlignelig
grensesnitt. Hvert element i det resulterende Kart
sorteres etter nøkkelen. I dette tilfellet vil produksjonen være:
Barney = øl, Homer = TV, Lenny = Carl, Moe = hagle
Husk imidlertid: hvis objektet ikke implementeres Sammenlignelig
, a ClassCastException
vil bli kastet.
Sortere et sett med TreeSet
De Sett
grensesnittet er ansvarlig for lagring av unike verdier, men når vi bruker TreeSet-implementeringen, blir innsatte elementer automatisk sortert når vi legger til dem:
public class TreeSetExample {public static void main (String ... barney) {Set simpsonsCharacters = new TreeSet (); simpsonsCharacters.add (ny SimpsonCharacter ("Moe")); simpsonsCharacters.add (ny SimpsonCharacter ("Lenny")); simpsonsCharacters.add (ny SimpsonCharacter ("Homer")); simpsonsCharacters.add (ny SimpsonCharacter ("Barney")); System.out.println (simpsonsCharacters); }}
Resultatet fra denne koden er:
Barney, Homer, Lenny, Moe
Igjen, hvis vi bruker et objekt som ikke er det Sammenlignelig
, a ClassCastException
vil bli kastet.
Sortering med komparator
Hva om vi ikke vil bruke det samme sammenligne med()
metode fra POJO-klassen? Kan vi overstyre Sammenlignelig
metode for å bruke en annen logikk? Nedenfor er et eksempel:
public class BadExampleOfComparable {public static void main (String ... args) {List characters = new ArrayList (); SimpsonCharacter homer = new SimpsonCharacter ("Homer") {@Override public int compareTo (SimpsonCharacter simpson) {return this.name.length () - (simpson.name.length ()); }}; SimpsonCharacter moe = new SimpsonCharacter ("Moe") {@Override public int compareTo (SimpsonCharacter simpson) {return this.name.length () - (simpson.name.length ()); }}; characters.add (homer); characters.add (moe); Collections.sort (tegn); System.out.println (tegn); }}
Som du kan se, er denne koden komplisert og inneholder mye repetisjon. Vi måtte overstyre sammenligne med()
metode to ganger for samme logikk. Hvis det var flere elementer, måtte vi replikere logikken for hvert objekt.
Heldigvis har vi Comparator-grensesnittet, som lar oss koble fra sammenligne med()
logikk fra Java-klasser. Tenk på det samme eksemplet ovenfor omskrevet med Komparator
:
public class GoodExampleOfComparator {public static void main (String ... args) {List characters = new ArrayList (); SimpsonCharacter homer = ny SimpsonCharacter ("Homer"); SimpsonCharacter moe = ny SimpsonCharacter ("Moe"); characters.add (homer); characters.add (moe); Collections.sort (tegn, (Comparator. ComparingInt (character1 -> character1.name.length ()) .thenComparingInt (character2 -> character2.name.length ()))); System.out.println (tegn); }}
Disse eksemplene viser hovedforskjellen mellom Sammenlignelig
og Komparator
.
Bruk Sammenlignelig
når det er en enkelt standard sammenligning for objektet ditt. Bruk Komparator
når du trenger å omgå et eksisterende sammenligne med()
, eller når du trenger å bruke spesifikk logikk på en mer fleksibel måte. Komparator
løsner sorteringslogikken fra objektet ditt og inneholder sammenligne med()
logikk i din sortere()
metode.
Bruke Comparator med en anonym indre klasse
I dette neste eksemplet bruker vi en anonym indre klasse for å sammenligne verdien på objekter. An anonym indre klasse, i dette tilfellet, er hvilken som helst klasse som implementeres Komparator
. Å bruke det betyr at vi ikke er bundet til å sette i gang en navngitt klasse som implementerer et grensesnitt; i stedet implementerer vi sammenligne med()
metode inne i den anonyme indre klassen.
public class MarvelComparator {public static void main (String ... comparator) {List marvelHeroes = new ArrayList (); marvelHeroes.add ("SpiderMan"); marvelHeroes.add ("Wolverine"); marvelHeroes.add ("Xavier"); marvelHeroes.add ("Cyclops"); Collections.sort (marvelHeroes, new Comparator () {@Override public int compare (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); }}
Mer om indre klasser
An anonym indre klasse er rett og slett enhver klasse hvis navn ikke betyr noe, og som implementerer grensesnittet vi erklærer. Så i eksemplet, det nye Komparator
er faktisk instantiering av en klasse som ikke har et navn, som implementerer metoden med den logikken vi ønsker.
Bruke Comparator med lambdauttrykk
Anonyme indre klasser er verbose, noe som kan forårsake problemer i koden vår. I Komparator
grensesnitt, kan vi bruke lambdauttrykk for å forenkle og gjøre koden lettere å lese. For eksempel kan vi endre dette:
Collections.sort (vidunder, ny Comparator () {@ Override offentlig int sammenligne (String hero1, String hero2) {return hero1.compareTo (hero2);}});
til dette:
Collections.sort (vidunder, (m1, m2) -> m1.compareTo (m2));
Mindre kode og samme resultat!
Utgangen av denne koden vil være:
Cyclops SpiderMan Wolverine Xavier
Vi kan gjøre koden enda enklere ved å endre denne:
Collections.sort (vidunder, (m1, m2) -> m1.compareTo (m2));
til dette:
Collections.sort (vidunder, Comparator.naturalOrder ());
Lambda-uttrykk i Java
Lær mer om lambdauttrykk og andre funksjonelle programmeringsteknikker i Java.
Er de viktigste Java-klassene sammenlignbare?
Mange kjerne Java-klasser og objekter implementerer Sammenlignelig
grensesnitt, noe som betyr at vi ikke trenger å implementere sammenligne med()
logikk for disse klassene. Her er noen kjente eksempler:
String
offentlig sluttklasse String implementerer java.io.Serializable, Comparable, CharSequence {...
Heltall
offentlig sluttklasse Heltall utvider Antall redskaper Sammenlignbare {...
Dobbelt
offentlig endelig klasse Dobbelt utvider Antall redskaper Sammenlignelig {...
Det er mange andre. Jeg oppfordrer deg til å utforske Java-kjerneklassene for å lære viktige mønstre og konsepter.
Ta den sammenlignbare grensesnittutfordringen!
Test det du har lært ved å finne ut resultatet av følgende kode. Husk at du lærer best hvis du løser denne utfordringen selv ved å studere den. Når du har nådd svaret, kan du sjekke svaret nedenfor. Du kan også kjøre dine egne tester for å absorbere konseptene fullt ut.
public class SortComparableChallenge {public static void main (String ... doYourBest) {Set set = new TreeSet (); set.add (nye Simpson ("Homer")); set.add (nye Simpson ("Marge")); set.add (nye Simpson ("Lisa")); set.add (nye Simpson ("Bart")); set.add (nye Simpson ("Maggie")); Listeliste = ny ArrayList (); list.addAll (sett); Collections.reverse (liste); list.forEach (System.out :: println); } statisk klasse Simpson implementerer Comparable {String name; offentlig Simpson (strengnavn) {this.name = navn; } public int compareTo (Simpson simpson) {return simpson.name.compareTo (this.name); } offentlig streng til streng () {returner dette.navn; }}}
Hva er utdataene fra denne koden?
A) Bart Homer Lisa Maggie Marge B) Maggie Bart Lisa Marge Homer C) Marge Maggie Lisa Homer Bart D) Ubestemt