How to use Comparator in Java to sort

后端 未结 14 1795
时光取名叫无心
时光取名叫无心 2020-11-22 02:19

I learned how to use the comparable but I\'m having difficulty with the Comparator. I am having a error in my code:

Exception in thread \"main\" java.lang.C         


        
相关标签:
14条回答
  • 2020-11-22 02:46

    The solution can be optimized in following way: Firstly, use a private inner class as the scope for the fields is to be the enclosing class TestPeople so as the implementation of class People won't get exposed to outer world. This can be understood in terms of creating an APIthat expects a sorted list of people Secondly, using the Lamba expression(java 8) which reduces the code, hence development effort

    Hence code would be as below:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    
    public class TestPeople {
        public static void main(String[] args) {
            ArrayList<People> peps = new ArrayList<>();// Be specific, to avoid
                                                        // classCast Exception
    
            TestPeople test = new TestPeople();
    
            peps.add(test.new People(123, "M", 14.25));
            peps.add(test.new People(234, "M", 6.21));
            peps.add(test.new People(362, "F", 9.23));
            peps.add(test.new People(111, "M", 65.99));
            peps.add(test.new People(535, "F", 9.23));
    
            /*
             * Collections.sort(peps);
             * 
             * for (int i = 0; i < peps.size(); i++){
             * System.out.println(peps.get(i)); }
             */
    
            // The above code can be replaced by followin:
    
            peps.sort((People p1, People p2) -> p1.getid() - p2.getid());
    
            peps.forEach((p) -> System.out.println(" " + p.toString()));
    
        }
    
        private class People {
            private int id;
    
            @Override
            public String toString() {
                return "People [id=" + id + ", info=" + info + ", price=" + price + "]";
            }
    
            private String info;
            private double price;
    
            public People(int newid, String newinfo, double newprice) {
                setid(newid);
                setinfo(newinfo);
                setprice(newprice);
            }
    
            public int getid() {
                return id;
            }
    
            public void setid(int id) {
                this.id = id;
            }
    
            public String getinfo() {
                return info;
            }
    
            public void setinfo(String info) {
                this.info = info;
            }
    
            public double getprice() {
                return price;
            }
    
            public void setprice(double price) {
                this.price = price;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:54

    Use People implements Comparable<People> instead; this defines the natural ordering for People.

    A Comparator<People> can also be defined in addition, but People implements Comparator<People> is not the right way of doing things.

    The two overloads for Collections.sort are different:

    • <T extends Comparable<? super T>> void sort(List<T> list)
      • Sorts Comparable objects using their natural ordering
    • <T> void sort(List<T> list, Comparator<? super T> c)
      • Sorts whatever using a compatible Comparator

    You're confusing the two by trying to sort a Comparator (which is again why it doesn't make sense that Person implements Comparator<Person>). Again, to use Collections.sort, you need one of these to be true:

    • The type must be Comparable (use the 1-arg sort)
    • A Comparator for the type must be provided (use the 2-args sort)

    Related questions

    • When to use Comparable vs Comparator
    • Sorting an ArrayList of Contacts

    Also, do not use raw types in new code. Raw types are unsafe, and it's provided only for compatibility.

    That is, instead of this:

    ArrayList peps = new ArrayList(); // BAD!!! No generic safety!
    

    you should've used the typesafe generic declaration like this:

    List<People> peps = new ArrayList<People>(); // GOOD!!!
    

    You will then find that your code doesn't even compile!! That would be a good thing, because there IS something wrong with the code (Person does not implements Comparable<Person>), but because you used raw type, the compiler didn't check for this, and instead you get a ClassCastException at run-time!!!

    This should convince you to always use typesafe generic types in new code. Always.

    See also

    • What is a raw type and why shouldn't we use it?
    0 讨论(0)
  • 2020-11-22 02:55

    There are a couple of awkward things with your example class:

    • it's called People while it has a price and info (more something for objects, not people);
    • when naming a class as a plural of something, it suggests it is an abstraction of more than one thing.

    Anyway, here's a demo of how to use a Comparator<T>:

    public class ComparatorDemo {
    
        public static void main(String[] args) {
            List<Person> people = Arrays.asList(
                    new Person("Joe", 24),
                    new Person("Pete", 18),
                    new Person("Chris", 21)
            );
            Collections.sort(people, new LexicographicComparator());
            System.out.println(people);
            Collections.sort(people, new AgeComparator());
            System.out.println(people);
        }
    }
    
    class LexicographicComparator implements Comparator<Person> {
        @Override
        public int compare(Person a, Person b) {
            return a.name.compareToIgnoreCase(b.name);
        }
    }
    
    class AgeComparator implements Comparator<Person> {
        @Override
        public int compare(Person a, Person b) {
            return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;
        }
    }
    
    class Person {
    
        String name;
        int age;
    
        Person(String n, int a) {
            name = n;
            age = a;
        }
    
        @Override
        public String toString() {
            return String.format("{name=%s, age=%d}", name, age);
        }
    }
    

    EDIT

    And an equivalent Java 8 demo would look like this:

    public class ComparatorDemo {
    
        public static void main(String[] args) {
            List<Person> people = Arrays.asList(
                    new Person("Joe", 24),
                    new Person("Pete", 18),
                    new Person("Chris", 21)
            );
            Collections.sort(people, (a, b) -> a.name.compareToIgnoreCase(b.name));
            System.out.println(people);
            Collections.sort(people, (a, b) -> a.age < b.age ? -1 : a.age == b.age ? 0 : 1);
            System.out.println(people);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 02:55

    You want to implement Comparable, not Comparator. You need to implement the compareTo method. You're close though. Comparator is a "3rd party" comparison routine. Comparable is that this object can be compared with another.

    public int compareTo(Object obj1) {
      People that = (People)obj1;
      Integer p1 = this.getId();
      Integer p2 = that.getid();
    
      if (p1 > p2 ){
       return 1;
      }
      else if (p1 < p2){
       return -1;
      }
      else
       return 0;
     }
    

    Note, you may want to check for nulls in here for getId..just in case.

    0 讨论(0)
  • 2020-11-22 02:56

    For the sake of completeness, here's a simple one-liner compare method:

    Collections.sort(people, new Comparator<Person>() {
        @Override
        public int compare(Person lhs, Person rhs) {  
            return Integer.signum(lhs.getId() - rhs.getId());  
        }
    });
    
    0 讨论(0)
  • 2020-11-22 02:59

    Here's a super short template to do the sorting right away :

    Collections.sort(people,new Comparator<Person>(){
       @Override
       public int compare(final Person lhs,Person rhs) {
         //TODO return 1 if rhs should be before lhs 
         //     return -1 if lhs should be before rhs
         //     return 0 otherwise (meaning the order stays the same)
         }
     });
    

    if it's hard to remember, try to just remember that it's similar (in terms of the sign of the number) to:

     lhs-rhs 
    

    That's in case you want to sort in ascending order : from smallest number to largest number.

    0 讨论(0)
提交回复
热议问题