Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Komparaattori: Tietojen Mukautettu Vertailu | Stream API:n Perusteet ja Toiminnalliset Ominaisuudet
Stream API

bookKomparaattori: Tietojen Mukautettu Vertailu

Tarkastellaan toista funktionaalista rajapintaa, Comparator, selvitetään kuinka se toteuttaa vertailun, ja ymmärretään ero Comparator- ja Comparable-rajapintojen välillä.

Mikä on Comparator?

Avainmetodi Comparator-funktionaalisessa rajapinnassa on:

int compare(T o1, T o2);

compare(T o1, T o2) -metodi palauttaa:

  • Negatiivinen luku, jos o1 on pienempi kuin o2;
  • Nolla, jos o1 ja o2 ovat yhtä suuret;
  • Positiivinen luku, jos o1 on suurempi kuin o2.

Käytännön sovellus

Toteutetaan Book-olioiden lajittelu käyttäen Comparator-rajapintaa. Sen sijaan, että vertailumenetelmä toteutettaisiin suoraan Book-luokassa, käytetään Comparator-rajapinnan staattisia metodeja lajittelulogiikan määrittämiseen.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
package com.example; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Book> books = new ArrayList<>(); books.add(new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925)); books.add(new Book("To Kill a Mockingbird", "Harper Lee", 1960)); books.add(new Book("1984", "George Orwell", 1949)); // Sort by title books.sort(Comparator.comparing(Book::getTitle)); System.out.println("Sorted by title: " + books); System.out.println("------------------------"); // Sort by author books.sort(Comparator.comparing(Book::getAuthor)); System.out.println("Sorted by author: " + books); } } class Book { private String title; private String author; private int year; public Book(String title, String author, int year) { this.title = title; this.author = author; this.year = year; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } @Override public String toString() { return title + " by " + author + " (" + year + ")"; } }

Tässä esimerkissä käytetään Comparator-rajapintaa books-listan lajitteluun. Mutta miksi käytettiin comparing()-metodia compare()-metodin sijaan?

Jos haluat käyttää compare()-metodia, sinun täytyy luoda Comparator-olio ja toteuttaa compare-metodi.

public static Comparator<Book> titleComparator = new Comparator<Book>() {
    @Override
    public int compare(Book b1, Book b2) {
        return b1.getTitle().compareTo(b2.getTitle());
    }
};

Tämä koodi määrittelee Comparator<Book>-olion anonyymin luokan avulla vertailemaan kahta Book-oliota niiden title-kentän perusteella.

Koska String toteuttaa Comparable-rajapinnan, käytetään compareTo()-metodia vertailemaan otsikoita leksikografisesti, jolloin palautetaan negatiivinen, nolla tai positiivinen arvo.

Vaihtoehtoisesti saman lopputuloksen voi saavuttaa lambda-lausekkeella ytimekkäämpään toteutukseen:

(b1, b2) -> b1.getTitle().compareTo(b2.getTitle());

Mutta on olemassa vielä yksinkertaisempi tapa: käyttämällä Comparator.comparing() metodia. Tämä metodi hoitaa vertailulogiikan automaattisesti puolestasi, tehden siitä luettavamman ja ytimekkäämmän.

Sinun tarvitsee vain välittää metodiviittaus, joka poimii kentän vertailua varten.

Comparator.comparing(Book::getTitle)

Listan sort() metodi kutsuu annettua Comparator-oliota, joka puolestaan määrittää alkioiden järjestyksen vertailemalla niitä annettujen metodien palauttamien arvojen perusteella.

Monikriteerinen lajittelu

Kun on tarpeen lajitella useamman kriteerin perusteella, voidaan käyttää thenComparing-metodia:

books.sort(
       Comparator.comparing(Book::getYear) // First by year
           .thenComparing(Book::getTitle) // Then by title
);

Tämä esimerkki havainnollistaa, kuinka kirjalista voidaan lajitella ensin julkaisuvuoden (year) ja sitten nimen (title) perusteella. Lajitteluprosessi vertaa ensin kirjoja niiden year-kentän mukaan, ja jos kahdella kirjalla on sama year, ne järjestetään title-kentän perusteella lopulliseen järjestykseen.

Käänteinen lajittelu

Lajittelujärjestyksen kääntäminen Javassa on hyödyllistä, kun halutaan lajitella ensin yhden kriteerin mukaan ja sitten muuttaa järjestystä seuraavan kriteerin kohdalla.

reversed()- ja Comparator.reverseOrder()-metodit mahdollistavat lajittelusuunnan hallinnan, mutta ne toimivat eri tavoin.

books.sort(
    Comparator.comparing(Book::getYear).reversed() // Sort by year (descending)
        .thenComparing(Book::getTitle, Comparator.reverseOrder()) // Then by title (descending)
);

Kirjat lajitellaan ensin niiden julkaisuvuoden year mukaan laskevassa järjestyksessä käyttäen reversed(). Jos usealla kirjalla on sama year, thenComparing() lajittelee ne title mukaan käänteisessä aakkosjärjestyksessä käyttäen Comparator.reverseOrder().

Tämä varmistaa, että uusimmat kirjat näkyvät ensin, ja saman year sisällä titles järjestetään Z:stä A:han.

Erot Comparable- ja Comparator-rajapintojen välillä

Käytä Comparable-rajapintaa, kun luokalla on luonnollinen järjestys, kuten lajittelu yhden kentän perusteella. Käytä Comparator-rajapintaa, kun lajittelet useiden kriteerien mukaan tai kun sinun täytyy määrittää räätälöity järjestys olioille.

1. Milloin käytetään Comparable-rajapintaa?

2. Milloin käytetään Comparator-rajapintaa?

question mark

Milloin käytetään Comparable-rajapintaa?

Select the correct answer

question mark

Milloin käytetään Comparator-rajapintaa?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 1. Luku 9

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

Suggested prompts:

Can you explain the main differences between Comparator and Comparable?

How do I choose between using Comparator and Comparable in my code?

Can you show an example of sorting with Comparable?

Awesome!

Completion rate improved to 2.33

bookKomparaattori: Tietojen Mukautettu Vertailu

Pyyhkäise näyttääksesi valikon

Tarkastellaan toista funktionaalista rajapintaa, Comparator, selvitetään kuinka se toteuttaa vertailun, ja ymmärretään ero Comparator- ja Comparable-rajapintojen välillä.

Mikä on Comparator?

Avainmetodi Comparator-funktionaalisessa rajapinnassa on:

int compare(T o1, T o2);

compare(T o1, T o2) -metodi palauttaa:

  • Negatiivinen luku, jos o1 on pienempi kuin o2;
  • Nolla, jos o1 ja o2 ovat yhtä suuret;
  • Positiivinen luku, jos o1 on suurempi kuin o2.

Käytännön sovellus

Toteutetaan Book-olioiden lajittelu käyttäen Comparator-rajapintaa. Sen sijaan, että vertailumenetelmä toteutettaisiin suoraan Book-luokassa, käytetään Comparator-rajapinnan staattisia metodeja lajittelulogiikan määrittämiseen.

Main.java

Main.java

copy
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
package com.example; import java.util.List; import java.util.ArrayList; import java.util.Comparator; public class Main { public static void main(String[] args) { List<Book> books = new ArrayList<>(); books.add(new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925)); books.add(new Book("To Kill a Mockingbird", "Harper Lee", 1960)); books.add(new Book("1984", "George Orwell", 1949)); // Sort by title books.sort(Comparator.comparing(Book::getTitle)); System.out.println("Sorted by title: " + books); System.out.println("------------------------"); // Sort by author books.sort(Comparator.comparing(Book::getAuthor)); System.out.println("Sorted by author: " + books); } } class Book { private String title; private String author; private int year; public Book(String title, String author, int year) { this.title = title; this.author = author; this.year = year; } public String getTitle() { return title; } public String getAuthor() { return author; } public int getYear() { return year; } @Override public String toString() { return title + " by " + author + " (" + year + ")"; } }

Tässä esimerkissä käytetään Comparator-rajapintaa books-listan lajitteluun. Mutta miksi käytettiin comparing()-metodia compare()-metodin sijaan?

Jos haluat käyttää compare()-metodia, sinun täytyy luoda Comparator-olio ja toteuttaa compare-metodi.

public static Comparator<Book> titleComparator = new Comparator<Book>() {
    @Override
    public int compare(Book b1, Book b2) {
        return b1.getTitle().compareTo(b2.getTitle());
    }
};

Tämä koodi määrittelee Comparator<Book>-olion anonyymin luokan avulla vertailemaan kahta Book-oliota niiden title-kentän perusteella.

Koska String toteuttaa Comparable-rajapinnan, käytetään compareTo()-metodia vertailemaan otsikoita leksikografisesti, jolloin palautetaan negatiivinen, nolla tai positiivinen arvo.

Vaihtoehtoisesti saman lopputuloksen voi saavuttaa lambda-lausekkeella ytimekkäämpään toteutukseen:

(b1, b2) -> b1.getTitle().compareTo(b2.getTitle());

Mutta on olemassa vielä yksinkertaisempi tapa: käyttämällä Comparator.comparing() metodia. Tämä metodi hoitaa vertailulogiikan automaattisesti puolestasi, tehden siitä luettavamman ja ytimekkäämmän.

Sinun tarvitsee vain välittää metodiviittaus, joka poimii kentän vertailua varten.

Comparator.comparing(Book::getTitle)

Listan sort() metodi kutsuu annettua Comparator-oliota, joka puolestaan määrittää alkioiden järjestyksen vertailemalla niitä annettujen metodien palauttamien arvojen perusteella.

Monikriteerinen lajittelu

Kun on tarpeen lajitella useamman kriteerin perusteella, voidaan käyttää thenComparing-metodia:

books.sort(
       Comparator.comparing(Book::getYear) // First by year
           .thenComparing(Book::getTitle) // Then by title
);

Tämä esimerkki havainnollistaa, kuinka kirjalista voidaan lajitella ensin julkaisuvuoden (year) ja sitten nimen (title) perusteella. Lajitteluprosessi vertaa ensin kirjoja niiden year-kentän mukaan, ja jos kahdella kirjalla on sama year, ne järjestetään title-kentän perusteella lopulliseen järjestykseen.

Käänteinen lajittelu

Lajittelujärjestyksen kääntäminen Javassa on hyödyllistä, kun halutaan lajitella ensin yhden kriteerin mukaan ja sitten muuttaa järjestystä seuraavan kriteerin kohdalla.

reversed()- ja Comparator.reverseOrder()-metodit mahdollistavat lajittelusuunnan hallinnan, mutta ne toimivat eri tavoin.

books.sort(
    Comparator.comparing(Book::getYear).reversed() // Sort by year (descending)
        .thenComparing(Book::getTitle, Comparator.reverseOrder()) // Then by title (descending)
);

Kirjat lajitellaan ensin niiden julkaisuvuoden year mukaan laskevassa järjestyksessä käyttäen reversed(). Jos usealla kirjalla on sama year, thenComparing() lajittelee ne title mukaan käänteisessä aakkosjärjestyksessä käyttäen Comparator.reverseOrder().

Tämä varmistaa, että uusimmat kirjat näkyvät ensin, ja saman year sisällä titles järjestetään Z:stä A:han.

Erot Comparable- ja Comparator-rajapintojen välillä

Käytä Comparable-rajapintaa, kun luokalla on luonnollinen järjestys, kuten lajittelu yhden kentän perusteella. Käytä Comparator-rajapintaa, kun lajittelet useiden kriteerien mukaan tai kun sinun täytyy määrittää räätälöity järjestys olioille.

1. Milloin käytetään Comparable-rajapintaa?

2. Milloin käytetään Comparator-rajapintaa?

question mark

Milloin käytetään Comparable-rajapintaa?

Select the correct answer

question mark

Milloin käytetään Comparator-rajapintaa?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 1. Luku 9
some-alt