优雅地比较对象

优雅地比较对象


  1/**
  2 * Java 8 函数式接口{@link Comparator}配合
  3 * {@link Function}可以简化传统比较器的编写:
  4 * 
  5 * <pre>
  6 * &#64;Override
  7 * public int compareTo(Person p) {
  8 *     int cmp = this.lastname.compareTo(p.lastname);
  9 *     if (cmp != 0) {
 10 *         return cmp;
 11 *     }
 12 *     cmp = this.firstname.compareTo(p.firstname);
 13 *     if (cmp != 0) {
 14 *         return cmp;
 15 *     }
 16 *     return Long.compare(this.zipcode, p.zipcode);
 17 * }
 18 * </pre>
 19 * 
 20 * 可以简化为:
 21 * 
 22 * <pre>
 23 * &#64;Override
 24 * public int compareTo(Person p) {
 25 *     return Comparator
 26 *             .comparing((Function&lt;Person, String&gt;) p1 -> p1.lastname)
 27 *             .thenComparing(person -> person.firstname)
 28 *             .thenComparing(person -> person.zipcode)
 29 *             .compare(this, p);
 30 * }
 31 * </pre>
 32 * <p>
 33 * 此外,guava工具类{@link ComparisonChain}提供了更加易于理解和编写
 34 * (Java 8的函数式接口不易理解和编写)的优化比较器的方法:
 35 * 
 36 * <pre>
 37 * &#64;Override
 38 * public int compareTo(Person p) {
 39 *     return ComparisonChain.start()
 40 *             .compare(this.lastname, p.lastname)
 41 *             .compare(this.firstname, p.firstname)
 42 *             .compare(this.zipcode, p.zipcode)
 43 *             .result();
 44 * }
 45 * </pre>
 46 * <p>
 47 * 这种“链式分格”的方法调用在许多优秀的框架中都能看到
 48 *
 49 * @author wangy
 50 * @date 2021.01.26/0026 16:00
 51 */
 52public class CompareChain {
 53
 54    static class Person implements Comparable<Person> {
 55        String ln;
 56        String fn;
 57        long zipcode;
 58
 59        public Person(String lastname, String firstname, long zipcode) {
 60            this.ln = lastname;
 61            this.fn = firstname;
 62            this.zipcode = zipcode;
 63        }
 64
 65        /**
 66         * usage : a.compareTo(b)
 67         *
 68         * @param p object to compared
 69         * @return
 70         * 
 71         *         <pre>
 72         * a > b ==> positive value <br>
 73         * a = b ==> 0 <br>
 74         * a < b ==> negative value
 75         *         </pre>
 76         */
 77        @Override
 78        public int compareTo(Person p) {
 79
 80            // the old way can be replaced by guava ComparisonChain
 81
 82            /*
 83             * return ComparisonChain.start()
 84             * .compare(this.ln, p.ln)
 85             * .compare(this.fn, p.fn)
 86             * .compare(this.zipcode, p.zipcode)
 87             * .result();
 88             */
 89
 90            // The java 8 also offer Functional Interface to do this
 91            // But the usage of Function<T,U>
 92            // is a little bit complicated to understand
 93            return Comparator
 94                    .comparing(
 95                            (Function<Person, String>) person -> person.ln)
 96                    .thenComparing(person -> person.fn)
 97                    .thenComparing(person -> person.zipcode)
 98                    .compare(this, p);
 99        }
100    }
101
102    public static void main(String[] args) {
103        System.out.println("a".compareTo("b")); // -1
104
105        Person p1 = new Person("steve", "jobs", 520000);
106        Person p2 = new Person("steve", "jobs", 510000);
107        Person p3 = new Person("steve", "jobs", 530000);
108        Person p4 = new Person("steve", "jobs", 520000);
109
110        System.out.printf("p1 compares to p2: %d\n", p1.compareTo(p2));
111        System.out.printf("p1 compares to p3: %d\n", p1.compareTo(p3));
112        System.out.printf("p1 compares to p4: %d\n", p1.compareTo(p4));
113
114    }
115}