Java - interface Comparator vs. interface Comparable

By sunwc 2023-03-27 Java

interface java.lang.Comparable override compartTo() 自然排序

  • override compareTo(obj) 的規則:
    • 如果當前物件this大於傳入物件obj,則回傳正整數
    • 如果當前物件this小於傳入物件obj,則回傳負整數
    • 如果當前物件this等於傳入物件obj,則回傳0 實現 interface Comparable 的有String, wrapper class, java.util.Date等類別,也因為如此它們都可以進行排序
public class Date
    implements java.io.Serializable, Cloneable, Comparable<Date> {
}
Date date1 = new Date(2023-1900, 3-1,27);
Date date2 = new Date(2023-1900, 8-1,27);

System.out.println(date2.compareTo(date1)); // 1

自定義類 implements Comparable override compareTo() 進行物件排序

/**
 * 商品類
 * @author sunwc
 * @create 2023-03-27 上午 11:27
 */
public class Goods implements Comparable {

    private String name;
    private int price;

    public Goods(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Goods{");
        sb.append("name='").append(name).append('\'');
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }

    /**
     * 指定商品比較大小的方式:按照價格從低到高排序
     * @param o
     * @return
     */
    @Override
    public int compareTo(Object o) {
        if (o instanceof Goods) {
            Goods goods = (Goods) o;

            // 方式一
            if (this.price > goods.price) {
                return 1;
            } else if (this.price < goods.price) {
                return -1;
            } else {
                // return  0;
                // 價格相同的還可以再用名稱作為排序條件
                return this.name.compareTo(goods.name);
            }
            // 方式二
//            return  Double.compare(this.price, goods.price);
        }
        throw new RuntimeException("傳入的資料型態不符");

    }



}

/**
 * 商品排序測試類
 */
class GoodsTest {

    @Test
    public void comparableTest() {
        Goods[] manyMouse = new Goods[6];
        manyMouse[0] = new Goods("microsoft", 600);
        manyMouse[1] = new Goods("lenovo", 400);
        manyMouse[2] = new Goods("logitech", 800);
        manyMouse[3] = new Goods("steelseries", 500);
        manyMouse[4] = new Goods("kinyo", 500);
        manyMouse[5] = new Goods("cherry", 500);

        // 若要使用Arrays.sort()對自定義物件陣列進行小到大排序,自定義類別要先覆寫 compareTo方法
        Arrays.sort(manyMouse);

        System.out.println(Arrays.toString(manyMouse));
    }
}

自定義物件排序後 輸出結果

[Goods{name='lenovo', price=400}, Goods{name='cherry', price=500}, Goods{name='kinyo', price=500}, Goods{name='steelseries', price=500}, Goods{name='microsoft', price=600}, Goods{name='logitech', price=800}]

interface java.util.Comparator 定制排序

使用匿名實現類 override compare()

  • override compare(Object obj1, Object obj2) 的規則,比較obj1和obj2大小:
    • 如果obj1大於obj2,則回傳正整數
    • 如果obj1小於obj2,則回傳負整數
    • 如果obj1等於obj2,則回傳0
@Test
  public void comparatorTest() {

      Goods[] manyMouse = new Goods[6];
      manyMouse[0] = new Goods("microsoft", 600);
      manyMouse[1] = new Goods("lenovo", 400);
      manyMouse[2] = new Goods("logitech", 800);
      manyMouse[3] = new Goods("steelseries", 500);
      manyMouse[4] = new Goods("kinyo", 500);
      manyMouse[5] = new Goods("cherry", 500);

      // 若要使用Arrays.sort()對自定義物件陣列進行大到小排序,匿名實現類別要先覆寫 compare方法
      // 條件:先按照產品名稱從低到高、再按照價格從高到低
      Arrays.sort(manyMouse, new Comparator<Goods>() {
          @Override
          public int compare(Goods o1, Goods o2) {
              String s1 = String.valueOf(o1.getName().charAt(0));
              String s2 = String.valueOf(o2.getName().charAt(0));

              // name first character 相同
            if (s1.equals(s2)) {
                // 價格從高到低(compare()原邏輯從低到高,所以要加負號變相反)
                return -Integer.compare(o1.getPrice(), o2.getPrice());
            } else {
                // name first character 不同
                // 名稱從低到高(compareTo()默認從低到高)
                return o1.getName().compareTo(o2.getName());
            }
          }
      });

      System.out.println(Arrays.toString(manyMouse));

  }

定制排序後 輸出結果:

[Goods{name='cherry', price=500}, Goods{name='kinyo', price=500}, Goods{name='logitech', price=800}, Goods{name='lenovo', price=400}, Goods{name='microsoft', price=600}, Goods{name='steelseries', price=500}]

總結

interface Comparable vs. interface Comparator

Comparable 的實現類別在任何位置都可以比較大小; Comparator 的 匿名實現類是屬於臨時性的比較