Interface Comparable (java.lang.Comparable) adalah sebuah interface yang berjanji (sebenarnya memberikan kontrak
) bahwa semua kelas yang mengimplement dirinya akan dapat di-naturally order. Sungguh membingungkan…
Ok.. mari kita buat lebih mudah dengan skenario ini. Misalkan anda punya kelas Person dan anda membuat segudang instans dari Person. Bagaimana caranya anda mengurutkan instans Person yang segudang ini?” Saya harap anda tidak berpikir untuk mengimplementasi Bubble Sort atau Quick Sort atau algoritma sorting lainnya
.. Untungnya, Java memiliki sebuah kelas yang berguna untuk masalah ini, yaitu kelas Collections (tentang kelas Collections ini sendiri akan kita bahas di post lain). Kelas ini memiliki sebuah method canggih yang bernama SORT. Horeee!! Masalah dapat diselesaikan.
Akan tetapi… method sort memiliki konstrain yang harus dipenuhi.. yaitu “Method ini hanya bisa men-sort kumpulan objek yang comparable”. Dengan kata lain, objek yang ingin anda sort harus mengimplement interface Comparable. Tetapi mengapa harus Comparable? Karena memang desainnya seperti itu
. Bercanda.., yang sebenarnya adalah karena interface Comparable memiliki method compareTo(T t) yang akan digunakan oleh method sort.
Sekarang, kita akan membahas teknisnya. Method compareTo akan mengembalikan integer. Karena integer memiliki tiga state, yaitu “Sama dengan 0″, “Besar dari 0″ dan “Kurang dari 0″, maka method sort menerjemahkan ketiga state tersebut sebagai berikut :
-
Sama dengan 0
Jika compareTo mengembalikan 0, maka method sort akan mengasumsikan bahwa objek ini (anggap saja namanya person1) sama dengan objek yang dibandingkan (anggap saja namanya person2). -
Besar dari 0
Jika compareTo mengembalikan integer yang lebih besar dari 0, maka method sort akan mengasumsikan bahwa person1 lebih besar dari person2 sehingga person1 akan ditempatkan di belakang person2 dalam list yang sudah disusun ulang : a, b, c.. person2, person1, x, y, z -
Kurang dari 0
Jika compareTo mengembalikan integer yang lebih kecil dari 0, maka method sort akan mengasumsikan bahwa person1 lebih kecil dari person2 sehingga person1 akan ditempatkan di depan person2 dalam list yang sudah disusun ulang : a, b, c.. person1, person2, x, y, z
Apakah asumsi ini hanya digunakan dalam kelas Collections? Tidak. Banyak kelas (kalau tidak semua) di Java dan mungkin juga di seluruh dunia menggunakan asumsi ini.
Jika method compareTo mengembalikan integer kurang dari 0, maka objek tersebut lebih kecil dibanding objek yang dibandingkan dan sebaliknya.
Jika method compareTo mengembalikan integer besar dari 0, maka objek itu dianggap sama. Tetapi asumsi ini bukanlah suatu konvensi. Di akhir post ini, saya akan memberikan contoh dimana asumsi yang dipakai adalah asumsi kebalikannya.
Lihatlah contoh ini :
public class Person implements Comparable<Person> {
private Integer id;
private String name;
private Date birthday;
@Override
public int compareTo(Person p) {
return id.compareTo(p.id);
}
}
Tetapi bagaimana jika kelas Person tidak mempunyai field id dan ingin membandingkan sebuah instans Person dengan instans Person lain menggunakan field name dan birthday? Coba lihat ini :
public class Person Person implements Comparable<Person> {
private String name;
private Date birthday;
@Override
public int compareTo(Person p) {
if (name.compareTo(p.name) != 0) return name.compareTo(p.name);
else return birthday.compareTo(p.birthday);
}
}
Dalam kode di atas, anda dapat melihat bahwa name dibandingkan terlebih dahulu ketimbang birthday. Ini adalah algoritma saya, anda dapat menggunakan algoritma anda sendiri yang sesuai dengan kebutuhan anda
Hal lain yang ingin saya beritahukan adalah :
-
Sebaiknya selalu implement Comparable
Kita tidak tahu siapa yang akana me-reuse kelas kita di masa nantinya dan di-reuse untuk apa. Tetapi satu hal yang pasti, mereka mungkin perlu membandingkan dua (atau lebih) instans dari kelas kita (untuk sorting, searching, atau apapun). -
Hasil yang dikeluarkan dari method compareTo harus mencerminkan hasil yang keluar dari method equals.
Anda akan terlihat bodoh jika anda mendesain suatu kelas dimana method compareTo menghasilkan nilai selain 0 tetapi method equals menghasilkan true
Ok. Diskusi tentang interface Comparable cukup sampai disini. Mari kita membicarakan interface Comparator. Sebenarnya, interface Comparable harus digunakan untuk natural order dan interface Comparator digunakan untuk total order, tetapi sulit untuk membuat dua buah strategi pengorderan. Jadi, mari kita abaikan saja tentang natural dan total order dan membicarakan tentang hal lain.
Untuk saat ini, anggap saja bahwa interface Comparable dipakai jika method compareTo diletakkan di dalam kelas itu sendiri dan interface Comparator digunakan jika kelas tersebut tidak mengimplement interface Comparable.
Ini adalah kelas Person dan kelas PersonComparator :
public class Person {
private String name;
private Date birthday;
// Getter & Setter
}
public class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
if (p1.getName().compareTo(p2.getName()) != 0) return p1.getName().compareTo(p2.getName());
else return p1.getBirthday().compareTo(p2.getBirthday());
}
}
Apakah ini berarti bahwa kita harus membuat sebuah kelas Comparator untuk setiap kelas yang tidak mengimplement Comparable? Ya… Tapi kita dapat memberikan semacam akal-akalan disini…, Coba lihat skenario ini..
public class Person {
// Attributes
// Getter & Setter
}
public class Pet {
// Attributes
// Getter & Setter
}
Misalkan anda mempunyai dua kelas yang tidak mengimplement Comparable. Agar dapat membandingkan instans dari kelas ini, anda seharusnya membuat minimal dua buah kelas Comparator dan ini tidak baik, karena partner anda akan bingung dengan banyaknya kelas yang tersebar di dalam package.
Sekarang, ketimbang memroduksi kelas Comparator sebanyak itu, anda dapat membuat semacam kelas OmniComparator, dan disinilah seninya
.
public class OmniComparator {
Comparator<Person> personComparator = new PersonComparator();
Comparator<Group> groupComparator = new GroupComparator();
// Getter -- No need to provide any setter
// Inner classes -- The trick goes here
class PersonComparator implements Comparator<Person>{
@Override
public int compare(Person p1, Person p2) {
// PUT YOUR CODE HERE
}
}
class GroupComparator implements Comparator<Group>{
@Override
public int compare(Group g1, Group g2) {
// PUT YOUR CODE HERE
}
}
}
Dengan cara ini.. anda tidak perlu beternak kelas. Cukup buat satu omniclass dan source code anda akan lebih mudah dibaca.
Bagaimana dengan kelas Collections? Bagaimana kita menggunakan method sort-nya? Jangan kuatir..
Desainer kelas Collections telah menyediakan jawabannya bagi kita. Kelas Collections class datang tidak hanya dengan satu method sort. Kelas ini datang dengan beberapa method sort dan salah satunya memungkinkan kita untuk menyortir objek-objek yang non-comparable asalkan kita menyediakan sebuah comparator untuk objek-objek tersebut. Method itu ialah sort(List list, Comparator c). Hoorrreee!!
Java telah menyediakan method untuk searching dan sorting melalui kelas Collections. Dengan mengombinasikan interface Comparable/Comparator dengan kelas Collections, kita dapat mengurangi effort yang kita keluarkan untuk coding tetapi dengan mudah dapat melakukan searching dan sorting.
Seperti yang telah dijanjikan sebelumnya, sekarang saya akan memberikan sebuah pertunjukan dimana integer positif tidak selalu berarti lebih besar dan integer negatif tidak selalu berarti lebih kecil. Mari kita lihat skenarionya :
Misalkan anda mempunyai beberapa tim dan juga poinnya secara berturut-turut seperti ini:
- Arsenal 19
- Chelsea 16
- Liverpool 17
- Man United 20
Bagaimana cara anda mengurutkan mereka menurut poinnya?
Apakah itu seperti ini :
1. Chelsea 16
2. Liverpool 17
3. Arsenal 19
4. Man United 20
atau begini :
1. Man United 20
2. Arsenal 19
3. Liverpool 17
4. Chelsea
OK, sekarang lihat kelas di bawah ini :
public class Team implements Comparable<Team>{
private int win;
private int draw;
private int lose;
// Getter & Setter
public int getPoint(){return win * 1 + draw;}
@Override
public int compareTo(Team t) {
// PUT YOUR CODE HERE
}
}
Di dalam liga sepakbola, biasanya tim diurutkan menurut jumlah poin, jumlah kemenangan, selisih gol dan seterusnya. Untuk mempermudah, kita anggap saja bahwa tim diurutkan hanya berdasarkan poinnya dan kita abaikan atribut yang lain.
Apakah anda sudah melihat sesuatu yang menarik disini? Yap. Jika sebuah tim memiliki poin lebih besar dari tim lain, maka tim tersebut haruslah ditempatkan di tempat yang lebih dulu di klasemen. Jadi, bagaimanakah implementasi dari method compareTo agar tim-tim ini dapat terurut dengan baik?
Apakah seperti ini?
@Override
public int compareTo(Team t) {
if (getPoint() == t.getPoint()){
// Another algorithm
}
else return getPoint() - t.getPoint();
}
Atau seperti ini?
@Override
public int compareTo(Team t) {
if (getPoint() == t.getPoint()){
// Another algorithm
}
else return t.getPoint() - getPoint();
}
Jika anda menggunakan method sort yang dibundel dalam kelas Collections, maka implementasi pertama akan menghasilkan sebuah klasemen aneh dimana tim dengan poin yang lebih besar akan ditempatkan lebih ke bawa dan ini sangatlah kejam
. Pada titik ini, saya ingin memberi tahu anda tentang nilai yang dikembalikan oleh method compareTo tidaklah strict kepada aturan “Positif adalah lebih besar, Negative adalah lebih kecil, dan 0 adalah sama”. Anda dapat mengubahnya sesuai dengan kasus yang anda hadapi.
Sekian post tentang interface Comparable dan Comparator. Terima kasih telah membaca







