Java Academy · Oppitunti

Comparable-rajapinta

Toteuta Comparable, jotta luokalla on luonnollinen järjestys, ja käytä sitä Collections.sort-metodin kanssa.

Oppitunti 1/413 vaihetta

Comparable-rajapinta on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Comparable-rajapinta

Comparable<T> antaa luokalle luonnollisen järjestyksen. Toteuttakaa se, jotta oliot voidaan järjestää menetelmillä Collections.sort() ja Arrays.sort() sekä TreeSetin kaltaisissa järjestetyissä kokoelmissa.

Comparablen toteuttaminen

Toteuttakaa compareTo(T other) palauttamaan negatiivinen arvo (this < other), nolla (samat) tai positiivinen arvo (this > other).

class Product implements Comparable<Product> {
    private final String name;
    private final double price;

    Product(String name, double price) {
        this.name = name; this.price = price;
    }

    @Override
    public int compareTo(Product other) {
        return Double.compare(this.price, other.price); // ascending by price
    }

    @Override public String toString() { return name + "($" + price + ")"; }
}

List<Product> products = new ArrayList<>(List.of(
    new Product("Mouse", 29.99),
    new Product("Laptop", 999.0),
    new Product("Keyboard", 79.99)
));
Collections.sort(products);
System.out.println(products); // [Mouse($29.99), Keyboard($79.99), Laptop($999.0)]

compareTo-sopimus

Comparablen oikea toteutus edellyttää seuraavan sopimuksen täyttämistä:

  • Antisymmetrisyys: sgn(a.compareTo(b)) == -sgn(b.compareTo(a))
  • Transitiivisuus: jos a > b ja b > c, niin a > c
  • Yhdenmukaisuus: a.compareTo(b) == 0 tarkoittaa, että a.equals(b) on erittäin suositeltavaa toteuttaa totena

Primitiivien turvallinen vertaileminen

Älkää koskaan vähentäkö primitiivejä compareTo-menetelmässä, sillä kokonaislukujen ylivuoto voi tuottaa vääriä tuloksia. Käyttäkää menetelmiä Integer.compare(), Double.compare() ja niin edelleen.

// WRONG: integer subtraction can overflow
int compareTo(Player other) {
    return this.score - other.score; // overflow if scores differ by > Integer.MAX_VALUE
}

// CORRECT: use Integer.compare
int compareTo(Player other) {
    return Integer.compare(this.score, other.score);
}

// For strings: delegate to String.compareTo
int compareTo(Player other) {
    return this.name.compareTo(other.name); // String handles it correctly
}

Luonnollinen järjestys TreeSetissä

Comparable-rajapinnan toteuttavat luokat sijoitetaan automaattisesti järjestettyihin kokoelmiin, kuten TreeSet- ja TreeMap-rakenteisiin.

class Priority implements Comparable<Priority> {
    enum Level { LOW, MEDIUM, HIGH, CRITICAL }
    final Level level;
    final String task;
    Priority(Level level, String task) { this.level = level; this.task = task; }
    @Override
    public int compareTo(Priority other) {
        return this.level.compareTo(other.level); // enum ordinal order
    }
    @Override public String toString() { return level + ": " + task; }
}

TreeSet<Priority> queue = new TreeSet<>();
queue.add(new Priority(Priority.Level.CRITICAL, "Fix prod crash"));
queue.add(new Priority(Priority.Level.LOW, "Update docs"));
queue.add(new Priority(Priority.Level.HIGH, "Deploy feature"));
queue.forEach(System.out::println);
// LOW: Update docs
// HIGH: Deploy feature
// CRITICAL: Fix prod crash

Comparable usealla kentällä

Kun haluatte järjestää usean kentän perusteella, ketjuttakaa vertailut: ensisijainen kenttä ensin ja toissijainen, jos ensisijaiset arvot ovat samat.

class Employee implements Comparable<Employee> {
    final String dept, name;
    final double salary;

    Employee(String dept, String name, double salary) {
        this.dept = dept; this.name = name; this.salary = salary;
    }

    @Override
    public int compareTo(Employee other) {
        int deptCmp = this.dept.compareTo(other.dept);
        if (deptCmp != 0) return deptCmp;           // primary: by dept
        return this.name.compareTo(other.name);      // secondary: by name
    }
}

Comparablen ja equals-menetelmän yhdenmukaisuus

On erittäin suositeltavaa, joskaan ei pakollista, että a.compareTo(b) == 0 täsmälleen silloin, kun a.equals(b). Tämän rikkominen aiheuttaa hienovaraisia virheitä järjestetyissä joukoissa ja kartoissa.

// BigDecimal violates this: new BigDecimal("2.0").compareTo(new BigDecimal("2.00")) == 0
// but new BigDecimal("2.0").equals(new BigDecimal("2.00")) == false

// This causes TreeSet to treat them as equal (only one stored)
TreeSet<java.math.BigDecimal> set = new TreeSet<>();
set.add(new java.math.BigDecimal("2.0"));
set.add(new java.math.BigDecimal("2.00"));
System.out.println(set.size()); // 1 — compareTo-equal → same element

Järjestäminen Collections.sort-menetelmällä

Collections.sort() ja Arrays.sort() käyttävät Comparablen määrittämää luonnollista järjestystä.

List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
Collections.sort(names); // natural alphabetical order
System.out.println(names); // [Alice, Bob, Charlie]

String[] arr = {"banana", "apple", "cherry"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [apple, banana, cherry]

// Stream sorted() uses natural order
names.stream().sorted().forEach(System.out::println);

Comparable binäärihaussa

Collections.binarySearch() edellyttää, että lista on järjestetty luonnolliseen järjestykseen ja että alkiot toteuttavat Comparablen.

List<Integer> sorted = new ArrayList<>(List.of(1, 3, 5, 7, 9, 11));
int idx = Collections.binarySearch(sorted, 7);
System.out.println("Found 7 at index: " + idx); // 3

int missing = Collections.binarySearch(sorted, 4);
System.out.println("4 not found, insertion point: " + (-missing - 1)); // 2

Comparable ja Comparator

Tärkein ero:

  • Comparable: määrittää luokan oman luonnollisen järjestyksen – yksi järjestys luokkaa kohden
  • Comparator: määrittää ulkoisen järjestyksen – rajattomasti yhdisteltäviä järjestyksiä

Käytännössä: tulostaulukko

Tulostaulukko, joka käyttää Comparablea luonnolliseen pistemäärän mukaiseen laskevaan järjestykseen.

class LeaderboardEntry implements Comparable<LeaderboardEntry> {
    final String player;
    final int score;
    final long timestamp;

    LeaderboardEntry(String player, int score) {
        this.player = player; this.score = score;
        this.timestamp = System.nanoTime();
    }

    @Override
    public int compareTo(LeaderboardEntry other) {
        int scoreCmp = Integer.compare(other.score, this.score); // descending
        if (scoreCmp != 0) return scoreCmp;
        return Long.compare(this.timestamp, other.timestamp); // earlier = higher
    }

    @Override public String toString() { return player + ": " + score; }
}

TreeSet<LeaderboardEntry> board = new TreeSet<>();
board.add(new LeaderboardEntry("Alice", 950));
board.add(new LeaderboardEntry("Bob", 1200));
board.add(new LeaderboardEntry("Carol", 950));
board.forEach(System.out::println);
// Bob: 1200 / Alice: 950 / Carol: 950

Pikatarkistus

Mitä compareTo() palauttaa, kun nykyinen olio on pienempi kuin argumentti?

Kertaus: Comparable-rajapinta

Tärkeimmät asiat:

  • Toteuttakaa Comparable<T>, jotta luokalle määrittyy luonnollinen järjestys
  • compareTo palauttaa negatiivisen arvon (pienempi), nollan (sama) tai positiivisen arvon (suurempi)
  • Käyttäkää Integer.compare()- ja Double.compare()-menetelmiä – älkää koskaan vähentäkö arvoja ylivuotoriskin vuoksi
  • Ketjuttakaa vertailut usean kentän järjestämisessä: ensisijainen → toissijainen
  • Luonnollista järjestystä käyttävät Collections.sort, Arrays.sort, TreeSet ja TreeMap
  • Comparable määrittää YHDEN järjestyksen; käyttäkää Comparatoria useisiin järjestyksiin
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Comparable-rajapinta” ilmainen?

Kyllä – oppitunnin ”Comparable-rajapinta” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Comparable-rajapinta”?

Toteuta Comparable, jotta luokalla on luonnollinen järjestys, ja käytä sitä Collections.sort-metodin kanssa. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”Comparable-rajapinta”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Comparable-rajapinta
  2. Comparator ja lajittelu lambdoilla
  3. Monikenttälajittelu thenComparing-metodilla
  4. Taulukoiden ja kokoelmien lajittelu käytännössä
← Takaisin: Java Academy