Programavimas

Rūšiavimas naudojant „Java“ programą „Comparable“ ir „Comparator“

Programuotojams dažnai reikia rūšiuoti elementus iš duomenų bazės į kolekciją, masyvą ar žemėlapį. „Java“ galime įdiegti bet kokį norimo rūšiavimo algoritmą su bet kokiu tipu. Naudojant Palyginamas sąsaja ir palyginti su() metodą, galime rūšiuoti abėcėlės tvarka, Stygos ilgis, atvirkštinė abėcėlės tvarka arba skaičiai. Lyginamasis sąsaja leidžia mums daryti tą patį, bet lanksčiau.

Kad ir ką norėtume daryti, mes tiesiog turime žinoti, kaip įgyvendinti teisingą rūšiavimo logiką duotai sąsajai ir tipui.

Gaukite šaltinio kodą

Gaukite šio „Java Challenger“ kodą. Jūs galite atlikti savo testus, kol laikysitės pavyzdžių.

„Java“ sąrašo rūšiavimas su pasirinktiniu objektu

Savo pavyzdyje naudosime tą patį POJO, kurį iki šiol naudojome kitiems „Java Challengers“. Šiame pirmame pavyzdyje įgyvendiname „Comparable“ sąsają Simpsonas klasė, naudojant Simpsonas bendro tipo:

 klasės „Simpson“ įgyvendina „Palyginamą“ {String name; Simpsonas (eilutės pavadinimas) {this.name = vardas; } @Paisyti viešojo int palyginimo (Simpson simpson) {grąžinti this.name.compareTo (simpson.name); }} public class SimpsonSorting {public static void main (String ... sortingWithList) {Simpsonų sąrašas = naujas ArrayList (); simpsons.add (naujas SimpsonCharacter („Homeras“)); simpsons.add (naujas SimpsonCharacter („Marge“)); simpsons.add (naujas „SimpsonCharacter“ („Bartas“)); simpsons.add (naujas SimpsonCharacter ("Lisa")); Kolekcijos.rūšiuoti (simpsonai); simpsons.stream (). map (s -> s.name) .forEach (System.out :: print); Kolekcijos.reverse (simpsonai); simpsons.stream (). forEach (System.out :: print); }} 

Atkreipkite dėmesį, kad mes atmetėme „CompareTo“ () metodą ir perėjome į kitą Simpsonas objektas. Mes taip pat aplenkėme toString () metodas, kad būtų lengviau skaityti pavyzdį.

toString metodas rodo visą informaciją iš objekto. Kai atspausdinsime objektą, išvestis bus tokia, kokia buvo įdiegta toString ().

Palyginti () metodas

palyginti su() metodas lygina nurodytą objektą arba esamą egzempliorių su nurodytu objektu, kad nustatytų objektų tvarką. Štai kaip greitai pažvelgti palyginti su() darbai:

Jei palyginimas grįš

Tada ...

  >= 1

  this.name> simpson.name

  0

  this.name == simpson.name

  <= -1

  this.name <simpson.name

Mes galime naudoti tik klases, kurios yra panašios į rūšiuoti () metodas. Jei bandysime praeiti a Simpsonas kad neįgyvendina Palyginamas, gausime kompiliavimo klaidą.

rūšiuoti () metodas naudoja polimorfizmą praleidžiant bet kokį objektą, kuris yra Palyginamas. Tada objektai bus rūšiuojami, kaip tikėtasi.

Išvestis iš ankstesnio kodo būtų:

 Bartas Homeris Lisa Marge 

Jei norėtume pakeisti tvarką, galėtume pasikeisti rūšiuoti () dėl atvirkštinis (); iš:

 Kolekcijos.rūšiuoti (simpsonai); 

į:

 Kolekcijos.reverse (simpsonai); 

Diegimas atvirkštinis () metodas pakeistų ankstesnę išvestį į:

 Marge Lisa Homer Bart 

„Java“ masyvo rūšiavimas

„Java“ sistemoje galime rūšiuoti bet kokio tipo masyvą, jei tik jis įgyvendina Palyginamas sąsaja. Štai pavyzdys:

 public class ArraySorting {public static void main (String ... moeTavern) {int [] moesPints ​​= new int [] {9, 8, 7, 6, 1}; Masyvai.rūšiuoti (moesPints); Masyvai.stream (moesPints) .forEach (System.out :: print); Simpsonas [] simpsonas = naujasis Simpsonas [] {naujasis Simpsonas („Lisa“), naujasis Simpsonas („Homeras“)}; Masyvai.rūšiuoti (simpsonai); Masyvai.stream (simpsonai) .forEach (System.out :: println); }} 

Pirmajame rūšiuoti () iškvietimas, masyvas rūšiuojamas taip:

 1 6 7 8 9 

Antroje rūšiuoti () iškvietimas, jis rūšiuojamas taip:

 Homeras Liza 

Atminkite, kad pasirinktiniai objektai turi būti įgyvendinti Palyginamas kad būtų galima išrūšiuoti net kaip masyvą.

Ar galiu rūšiuoti objektus be „Palyginamas“?

Jei „Simpson“ objektas nebuvo įgyvendinamas Palyginamas, „ClassCastException“ bus išmestas. Jei atliksite tai kaip bandymą, pamatysite panašų į šį išvestį:

 Klaida: (16, 20) java: nerastas tinkamas metodas rūšiuoti (java.util.List) metodą java.util.Collections.sort (java.util.List) netaikomas (išvadų kintamasis T turi nesuderinamų ribų dėl lygybės apribojimų: com.javaworld.javachallengers.sortingcomparable.Simpson apatinės ribos: java.lang.Comparable) metodas java.util.Collections.sort (java.util.List, java.util.Comparator) netaikomas (negalima nuspręsti tipo kintamojo (-ų) ) T (faktinių ir oficialių argumentų sąrašai skiriasi ilgiu)) 

Šis žurnalas gali būti painus, bet nesijaudinkite. Tiesiog nepamirškite, kad a „ClassCastException“ bus mesta už bet kokį rūšiuojamą objektą, kuris neįgyvendina Palyginamas sąsaja.

Žemėlapio rūšiavimas naudojant TreeMap

„Java“ API apima daug klasių, kurios padeda rūšiuoti, įskaitant „TreeMap“. Žemiau pateiktame pavyzdyje mes naudojame Medžio žemėlapis rūšiuoti raktus į a Žemėlapis.

 public class TreeMapExample {public static void main (String ... barney) {Žemėlapio simpsonsCharacters = naujas TreeMap (); simpsonsCharacters.put (naujas SimpsonCharacter („Moe“), „shotgun“); simpsonsCharacters.put (naujas SimpsonCharacter ("Lenny"), "Carl"); simpsonsCharacters.put (naujas „SimpsonCharacter“ („Homeras“), „televizija“); simpsonsCharacters.put (naujas „SimpsonCharacter“ („Barney“), „alus“); System.out.println (simpsonsCharacters); }} 

Medžio žemėlapis naudoja palyginti su() metodas, kurį įgyvendino Palyginamas sąsaja. Kiekvienas gauto elemento Žemėlapis yra rūšiuojamas pagal raktą. Tokiu atveju išvestis būtų:

 Barnis = alus, Homeras = televizija, Lenny = Karlas, Moe = šautuvas 

Nepamirškite: jei objektas neįgyvendinamas Palyginamas, a „ClassCastException“ bus išmestas.

Rūšiavimo rūšiavimas naudojant „TreeSet“

Nustatyti sąsaja yra atsakinga už unikalių reikšmių saugojimą, tačiau, kai mes naudojame „TreeSet“ diegimą, įterpti elementai bus automatiškai rūšiuojami, kai mes juos pridėsime:

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

Šio kodo išvestis yra:

 Barney, Homeras, Lenny, Moe 

Vėlgi, jei mes naudojame objektą, kuris nėra Palyginamas, a „ClassCastException“ bus išmestas.

Rūšiavimas naudojant „Comparator“

Kas būtų, jei nenorėtume naudoti to paties palyginti su() metodas iš POJO klasės? Ar galėtume nepaisyti Palyginamas metodas naudoti kitą logiką? Žemiau pateikiamas pavyzdys:

 public class BadExampleOfComparable {public static void main (String ... args) {Sąrašo simboliai = new ArrayList (); „SimpsonCharacter homer“ = naujas „SimpsonCharacter“ („Homeris“) {@Paisyti viešąjį int palygintiTo („SimpsonCharacter simpson“) {grąžinti this.name.length () - (simpson.name.length ()); }}; „SimpsonCharacter moe“ = naujas „SimpsonCharacter“ („Moe“) {@Paisyti viešąjį int palygintiTo („SimpsonCharacter simpson“) {grąžinti this.name.length () - (simpson.name.length ()); }}; simboliai.add (homeras); simboliai.add (moe); Kolekcijos.rūšiuoti (simboliai); System.out.println (simboliai); }} 

Kaip matote, šis kodas yra sudėtingas ir apima daug pakartojimų. Turėjome nepaisyti palyginti su() metodas du kartus pagal tą pačią logiką. Jei būtų daugiau elementų, turėtume atkartoti kiekvieno objekto logiką.

Laimei, mes turime „Comparator“ sąsają, kuri leidžia mums atjungti palyginti su() logika iš „Java“ klasių. Apsvarstykite tą patį aukščiau pateiktą pavyzdį, perrašytą naudojant Palygintojas:

 viešoji klasė „GoodExampleOfComparator“ {public static void main (String ... args) {Sąrašo simboliai = new ArrayList (); „SimpsonCharacter Homer“ = naujas „SimpsonCharacter“ („Homeras“); „SimpsonCharacter moe“ = naujas „SimpsonCharacter“ („Moe“); simboliai.add (homeras); simboliai.add (moe); Rinkiniai.sort (simboliai, (Comparator. PalyginimasInt (simbolis1 -> simbolis1.pavadinimas.length ()) .tadaComparingInt (simbolis2 -> simbolis2.pavadinimas.ilgis ()))); System.out.println (simboliai); }} 

Šie pavyzdžiai rodo pagrindinį skirtumą Palyginamas ir Lyginamasis.

Naudokite Palyginamas kai yra vienas numatytasis jūsų objekto palyginimas. Naudokite Lyginamasiskai reikia apeiti esamą palyginti su()arba kai reikia naudoti konkrečią logiką lanksčiau. Palygintojas atjungia rūšiavimo logiką nuo jūsų objekto ir joje yra palyginti su() logika jūsų rūšiuoti () metodas.

„Comparator“ naudojimas naudojant anoniminę vidinę klasę

Šiame kitame pavyzdyje mes naudojame anoniminę vidinę klasę, kad palygintume objektų vertę. An anoniminė vidinė klasė, šiuo atveju yra bet kuri klasė, kuri įgyvendina Palygintojas. Naudojimasis juo reiškia, kad nesame įpareigoti įvardyti klasės, diegiančios sąsają; vietoj to mes įgyvendiname palyginti su() metodas anoniminės vidinės klasės viduje.

 public class MarvelComparator {public static void main (String ... Comparator) {Sąrašas marvelHeroes = new ArrayList (); marvelHeroes.add („Žmogus-voras“); marvelHeroes.add („Wolverine“); marvelHeroes.add („Xavier“); marvelHeroes.add („Kiklopas“); Collections.sort (marvelHeroes, new Comparator () {@Paisyti viešąjį int palyginimą (String hero1, String hero2) {return hero1.compareTo (hero2);}}); Kolekcijos.rūšiuoti (marvelHeroes, (m1, m2) -> m1.compareTo (m2)); Collections.sort (marvelHeroes, Comparator.naturalOrder ()); marvelHeroes.forEach (System.out :: print); }} 

Daugiau apie vidines klases

An anoniminė vidinė klasė yra tiesiog bet kuri klasė, kurios vardas neturi reikšmės ir kuri įgyvendina mūsų deklaruojamą sąsają. Taigi pavyzdyje naujas Lyginamasis iš tikrųjų yra klasės, neturinčios pavadinimo, pavyzdys, įgyvendinantis metodą norima logika.

Komparatoriaus naudojimas su lambda išraiškomis

Anoniminės vidinės klasės yra daugžodiškos, o tai gali sukelti problemų mūsų kode. Viduje konors Lyginamasis sąsają, mes galime naudoti lambda išraiškas, kad supaprastintume ir palengvintume kodo skaitymą. Pavyzdžiui, galėtume tai pakeisti:

 Collections.sort (stebuklas, naujas „Comparator“) {@Paisyti viešąjį int palyginimą („String hero1“, „String hero2“) {return hero1.compareTo (hero2);}}); 

šiam:

 Kolekcijos.rūšiuoti (stebuklas, (m1, m2) -> m1.compareTo (m2)); 

Mažiau kodo ir tas pats rezultatas!

Šio kodo išvestis būtų:

 Kiklopai „SpiderMan Wolverine Xavier“ 

Kodas galėtų būti dar paprastesnis, pakeitus tai:

 Kolekcijos.rūšiuoti (stebuklas, (m1, m2) -> m1.compareTo (m2)); 

šiam:

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

„Lambda“ išraiškos „Java“

Sužinokite daugiau apie „lambda“ išraiškas ir kitas funkcines „Java“ programavimo technikas.

Ar pagrindinės „Java“ klasės yra palyginamos?

Daugelis pagrindinių „Java“ klasių ir objektų įdiegia Palyginamas sąsaja, o tai reiškia, kad mes neturime įdiegti palyginti su() logika toms klasėms. Štai keletas žinomų pavyzdžių:

Stygos

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

Sveikasis skaičius

 viešosios galutinės klasės sveikasis skaičius pratęsiamas Skaičius įgyvendinamas Palyginami {… 

Dvigubai

 viešoji galutinė klasė Dvigubai pratęsia Skaičių padargai Palyginami {... 

Yra daugybė kitų. Raginu jus ištirti „Java“ pagrindines klases, kad sužinotumėte svarbius jų modelius ir sąvokas.

Priimkite „Comparable interface“ iššūkį!

Išbandykite tai, ką išmokote, išsiaiškindami šio kodo išvestį. Atminkite, kad geriausiai išmoksite, jei išspręsite šį iššūkį patys, tik jį studijuodami. Gavę atsakymą, galite patikrinti toliau pateiktą atsakymą. Taip pat galite atlikti savo testus, kad visiškai įsisąmonintumėte sąvokas.

 public class SortComparableChallenge {public static void main (String ... doYourBest) {Set set = new TreeSet (); set.add (naujasis Simpsonas („Homeras“)); set.add (naujas Simpsonas („Marge“)); set.add (naujasis Simpsonas („Lisa“)); set.add (naujas Simpsonas („Bartas“)); set.add (naujas Simpsonas („Maggie“)); Sąrašo sąrašas = naujas „ArrayList“ (); list.addAll (rinkinys); Kolekcijos.reverse (sąrašas); list.forEach (System.out :: println); } statinė klasė „Simpson“ įgyvendina „Palyginamą“ {String name; viešasis Simpsonas (eilutės pavadinimas) {this.name = vardas; } public int CompareTo (Simpson simpson) {grąžinti simpson.name.compareTo (this.name); } public String toString () {return this.name; }}} 

Kuris yra šio kodo išvestis?

 A) Bart Homer Lisa Maggie Marge B) Maggie Bart Lisa Marge Homer C) Marge Maggie Lisa Homer Bart D) Neapibrėžta