Objektumok összehasonlítása Java-ban

1. Bemutatkozás

Az objektumok összehasonlítása elengedhetetlen jellemzője az objektum-orientált programozási nyelveknek.

Ebben az oktatóanyagban megvizsgáljuk a Java nyelv néhány olyan tulajdonságát, amelyek lehetővé teszik az objektumok összehasonlítását. Ezenkívül megvizsgáljuk az ilyen szolgáltatásokat a külső könyvtárakban.

2. == és != Operátorok

Kezdjük a == és != operátorok, amelyek meg tudják állapítani, hogy két Java objektum azonos-e vagy sem.

2.1. Primitívek

A primitív típusok esetében ugyanaz az egyenlő értéket jelent:

assertThat (1 == 1) .is True ();

Az automatikus kicsomagolásnak köszönhetően ez akkor is működik, ha egy primitív értéket összehasonlítunk burkoló típusú megfelelőjével:

Egész a = új egész szám (1); assertThat (1 == a) .isTrue ();

Ha két egész számnak különböző az értéke, akkor a == üzemeltető visszatérne hamis, amíg a != üzemeltető visszatérne igaz.

2.2. Tárgyak

Tegyük fel, hogy kettőt akarunk összehasonlítani Egész szám burkolótípusok azonos értékkel:

Egész a = új egész szám (1); Egész b = új egész szám (1); assertThat (a == b) .isFalse ();

Két objektum összehasonlításával az objektumok értéke nem 1. Inkább a memória címeik a veremben amelyek különböznek, mivel mindkét objektum a új operátor. Ha kijelöltük volna a nak nek b, akkor más eredményünk lett volna:

Egész a = új egész szám (1); Egész b = a; assertThat (a == b) .isTrue ();

Most nézzük meg, mi történik, amikor a Egész # értékOf gyári módszer:

Egész a = Integer.valueOf (1); Egész b = Integer.valueOf (1); assertThat (a == b) .isTrue ();

Ebben az esetben ugyanazoknak tekintik őket. Ez azért van, mert a értéke() módszer tárolja a Egész szám egy gyorsítótárban, hogy elkerülhető legyen túl sok azonos értékű burkolóobjektum létrehozása. Ezért a módszer ugyanazt adja vissza Egész szám például mindkét híváshoz.

A Java is ezt teszi Húr:

assertThat ("Hello!" == "Hello!"). isTrue ();

Ha azonban a új üzemeltető, akkor nem lennének ugyanazok.

Végül, kettő nulla a hivatkozások azonosak, míg a nemnulla objektum eltérõnek tekintendõ nulla:

assertThat (null == null) .isTrue (); assertThat ("Hello!" == null) .isFalse ();

Természetesen az esélyegyenlőség működtetőinek viselkedése korlátozó lehet. Mi van, ha két objektumot szeretnénk összehasonlítani, amelyek különböző címekre vannak feltérképezve, és mégis belső állapotuk alapján egyenlőnek tekinthetők? A következő szakaszokban megtudjuk, hogyan.

3. A # objektum megegyezik Módszer

Most beszéljünk a tágabb értelemben vett egyenlőségről egyenlő () módszer.

Ezt a módszert a Tárgy osztályt úgy, hogy minden Java objektum örökölje. Alapértelmezés szerint, megvalósítása összehasonlítja az objektum memória címeket, tehát ugyanúgy működik, mint a == operátor. Mindazonáltal felülírhatjuk ezt a módszert annak meghatározása érdekében, hogy az egyenlőség mit jelent tárgyaink számára.

Először nézzük meg, hogyan viselkedik a meglévő objektumok, például Egész szám:

Egész a = új egész szám (1); Egész b = új egész szám (1); assertThat (a. egyenlő (b)). isTrue ();

A módszer továbbra is visszatér igaz amikor mindkét objektum azonos.

Meg kell jegyeznünk, hogy átmehetünk egy nulla objektum a metódus argumentumaként, de természetesen nem mint objektum, amelyre a metódust hívjuk.

Használhatjuk a egyenlő () módszer egy saját tárgyunkkal. Tegyük fel, hogy van egy Személy osztály:

public class Személy {private String keresztnév; privát karakterlánc vezetéknév; public Person (karakterlánc keresztnév, karakterlánc vezetéknév) {this.firstName = keresztnév; this.lastName = vezetékNév; }}

Felülírhatjuk a egyenlő () módszer erre az osztályra, hogy kettőt összehasonlíthassunk Személys belső adataik alapján:

@Orride public boolean egyenlő (Object o) if (ez == o) return true; ha (o == null 

További információért olvassa el a témával foglalkozó cikkünket.

4. A # objektum egyenlő Statikus módszer

Most nézzük meg a Objektumok # egyenlő statikus módszer. Korábban említettük, hogy nem tudjuk használni nulla mint az első objektum értéke egyébként a NullPointerException dobnák.

A egyenlő () módszere Tárgyak segítő osztály megoldja ezeket a problémákat. Két érvre van szükség, és összehasonlítja őket, kezelve is nulla értékek.

Hasonlítsuk össze Személy újból objektumokat hoz létre:

Joe személy = új személy ("Joe", "Portman"); Person joeAgain = new Person ("Joe", "Portman"); Person natalie = új személy ("Natalie", "Portman"); assertThat (Objektumok.egyenlő (joe, joeAgain)). isTrue (); assertThat (Objektumok.egyenlő (joe, natalie)). isFalse ();

Mint mondtuk, a módszer kezeli nulla értékek. Ezért, ha mindkét érv igen nulla vissza fog térni igaz, és ha csak az egyik nulla, akkor visszatér hamis.

Ez nagyon hasznos lehet. Tegyük fel, hogy egy opcionális születési dátumot szeretnénk hozzáadni a dátumhoz Személy osztály:

public Person (String keresztnév, String vezetéknév, LocalDate születési dátum) {this (keresztnév, vezetéknév); ez.születésiDátum = születésiDátum; }

Aztán frissítenünk kell a programot egyenlő () módszerrel, hanem nulla kezelése. Ezt úgy tehetjük meg, hogy ezt a feltételt hozzáadjuk a feltételekhez egyenlő () módszer:

birthDate == null? that.birthDate == null: birthDate.equals (that.birthDate);

Ha azonban számos nullázhatatlan mezőt felveszünk az osztályunkba, akkor ez nagyon rendetlenné válhat. Használni a Objektumok # egyenlő módszer a mi egyenlő () a megvalósítás sokkal tisztább és javítja az olvashatóságot:

Objektumok.egyenlőség (születési dátum, ez. Születési dátum);

5. Összehasonlítható Felület

Összehasonlító logikával objektumok meghatározott sorrendben is elhelyezhetők. A Hasonló felület lehetővé teszi számunkra az objektumok közötti sorrend meghatározását, annak megállapításával, hogy egy tárgy nagyobb-e, egyenlő vagy kisebb-e, mint egy másik.

A Hasonló az interfész általános és csak egy módszerrel rendelkezik, összehasonlítani(), amely egy általános típusú argumentumot vesz fel és egy int. A visszaadott érték negatív, ha ez alacsonyabb, mint az argumentum, 0, ha egyenlőek, és egyébként pozitívak.

Mondjuk, a mi Személy osztály, szeretnénk összehasonlítani Személy tárgyak vezetéknevük szerint:

public class Személy megvalósítja összehasonlítható {// ... @Orride public int CompareTo (Person o) {return this.lastName.compareTo (o.lastName); }}

A összehasonlítani() módszer negatív eredményt ad int ha a-val hívják Személy nagyobb vezetéknévvel, mint ez, nulla, ha ugyanaz a vezetéknév, és pozitív pozitív.

További információért tekintse meg a témáról szóló cikkünket.

6. Összehasonlító Felület

A Összehasonlító interfész általános és rendelkezik egy hasonlítsa össze metódus, amely két ilyen típusú általános argumentumot vesz fel és egy egész szám. Ezt a mintát már korábban láttuk a Hasonló felület.

Összehasonlító hasonló; azonban el van választva az osztály definíciójától. Ebből kifolyólag, annyit határozhatunk meg Összehasonlítók osztályra vágyunk, ahol csak egyet tudunk biztosítani Hasonló végrehajtás.

Képzeljük el, hogy van egy weboldalunk, amely táblázatnézetben jeleníti meg az embereket, és szeretnénk felajánlani a felhasználónak a lehetőséget, hogy a vezetéknevek helyett keresztnevek szerint rendezzék őket. Ez nem lehetséges Hasonló ha a jelenlegi megvalósításunkat is meg akarjuk tartani, de a sajátunkat is megvalósíthatnánk Összehasonlítók.

Hozzunk létre egy SzemélyÖsszehasonlító amely csak a keresztnevükön fogja összehasonlítani őket:

Összehasonlító összehasonlítByFirstNames = Összehasonlító.összehasonlítás (Személy :: getFirstName);

Válasszunk most egy Lista akik ezt használják Összehasonlító:

Joe személy = új személy ("Joe", "Portman"); Személy allan = új személy ("Allan", "Dale"); Személyek felsorolása = new ArrayList (); emberek.add (joe); emberek.add (allan); people.sort (hasonlítsaByFirstNames); állítaniThat (emberek) .tartalmazPontosan (allan, joe);

Vannak más módszerek is a Összehasonlító felületet használhatjuk összehasonlítani() végrehajtás:

@Override public int CompareTo (Person o) {return Comparator.comparing (Person :: getLastName) .thenComparing (Person :: getFirstName) .thenComparing (Person :: getBirthDate, Comparator.nullsLast (Comparator.naturalOrder ())). Összehasonlítás ( ez, o); }

Ebben az esetben először a vezetékneveket, majd a keresztneveket hasonlítjuk össze. Ezután összehasonlítjuk a születési dátumokat, de mivel érvénytelenek, meg kell mondanunk, hogyan kezeljük ezt, így adunk egy második érvet, amely elmondja, hogy ezeket a természetes sorrendjük szerint, de nulla értékek utoljára mennek.

7. Apache Commons

Vessünk egy pillantást az Apache Commons könyvtárra. Először importáljuk a Maven-függőséget:

 org.apache.commons commons-lang3 3.10 

7.1. ObjectUtils # notEqual Módszer

Először beszéljünk a ObjectUtils # notEqual módszer. Kettőn áll a vásár Tárgy érvek, annak megállapítása érdekében, hogy a sajátjuk szerint nem egyenlőek-e egyenlő () módszer megvalósítása. Ez is kezeli nulla értékek.

Használjuk újból Húr példák:

String a = új karakterlánc ("Hello!"); String b = új karakterlánc ("Hello World!"); assertThat (ObjectUtils.notEqual (a, b)). isTrue (); 

meg kell jegyezni, hogy ObjectUtils van egy egyenlő () módszer. Ez azonban elavult a Java 7 óta, amikor Objektumok # egyenlő megjelent

7.2. ObjectUtils # összehasonlítás Módszer

Most hasonlítsuk össze az objektum sorrendjét a ObjectUtils # összehasonlítás módszer. Ez egy általános módszer, amely kettőt igényel Hasonló az általános típusú argumentumok és egy Egész szám.

Lássuk ezt használva Húrok újra:

String first = új karakterlánc ("Hello!"); Második karakterlánc = új karakterlánc ("Hogy vagy?"); assertThat (ObjectUtils.compare (első, második)). isNegative ();

Alapértelmezés szerint a módszer kezeli nulla értékeket nagyobbnak tekintve. Túlterhelt verziót kínál, amely felajánlja ennek a viselkedésnek az inverzióját, és kevésbé tartja őket, figyelembe véve a logikai érv.

8. Guava

Most vessünk egy pillantást Guava-ra. Először importáljuk a függőséget:

 com.google.guava guava 29.0-jre 

8.1. Objektumok # egyenlőek Módszer

Az Apache Commons könyvtárhoz hasonlóan a Google is biztosít egy módszert annak meghatározására, hogy két objektum egyenlő-e, Objektumok # egyenlőek. Bár különböző megvalósításokkal rendelkeznek, ugyanazokat az eredményeket adják vissza:

String a = új karakterlánc ("Hello!"); String b = új karakterlánc ("Hello!"); assertThat (Objects.equal (a, b)). isTrue ();

Bár nincs elavultként megjelölve, a módszer JavaDoc-ja azt mondja, hogy elavultnak kell tekinteni, mivel a Java 7 Objektumok # egyenlő módszer.

8.2. Összehasonlítási módszerek

Most a guavai könyvtár nem kínál módszert két objektum összehasonlítására (a következő szakaszban meglátjuk, mit tehetünk ennek érdekében), de módszerekkel szolgál a primitív értékek összehasonlítására. Vegyük a Ints segítő osztály és nézze meg, hogyan összehasonlít () a módszer működik:

assertThat (Ints.compare (1, 2)). isNegative ();

Szokás szerint egy egész szám ez lehet negatív, nulla vagy pozitív, ha az első argumentum kisebb, egyenlő vagy nagyobb, mint a második. Hasonló módszerek léteznek az összes primitív típusnál, kivéve bájtokat.

8.3. ComparisonChain Osztály

Végül a guavai könyvtár felajánlja a ComparisonChain osztály, amely lehetővé teszi számunkra, hogy két tárgyat összehasonlítsunk az összehasonlítások láncolatán keresztül. Könnyen összehasonlíthatunk kettőt Személy objektumok utó- és vezetéknévvel:

Személy natalie = új Személy ("Natalie", "Portman"); Joe személy = új személy ("Joe", "Portman"); int CompareResult = ComparisonChain.start () .compare (natalie.getLastName (), joe.getLastName ()) .compare (natalie.getFirstName (), joe.getFirstName ()) .rezult (); assertThat (összehasonlítás eredménye) .isPositive ();

Az alapjául szolgáló összehasonlítást a összehasonlítani() metódus, így az argumentumok átkerültek a összehasonlít () a módszereknek primitíveknek vagy Hasonlós.

9. Következtetés

Ebben a cikkben megvizsgáltuk az Java-objektumok összehasonlításának különböző módjait. Megvizsgáltuk az egyformaság, az egyenlőség és a sorrend közötti különbséget. Megnéztük az Apache Commons és a Guava könyvtár megfelelő jellemzőit is.

Szokás szerint a cikk teljes kódja megtalálható a GitHubon.