views:

327

answers:

4

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.ClassCastException: New.People cannot be cast to java.lang.Comparable
 at java.util.Arrays.mergeSort(Unknown Source)
 at java.util.Arrays.sort(Unknown Source)
 at java.util.Collections.sort(Unknown Source)
 at New.TestPeople.main(TestPeople.java:18)

Here is my code:

import java.util.Comparator;

public class People implements Comparator{


 private int id;
 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;
 }

 public int compare(Object obj1, Object obj2) {
  Integer p1 = ((People)obj1).getid();
  Integer p2 = ((People)obj2).getid();

  if (p1 > p2 ){
   return 1;
  }
  else if (p1 < p2){
   return -1;
  }
  else
   return 0;
 }
}

import java.util.ArrayList;
import java.util.Collections;

public class TestPeople {

  public static void main(String[] args) {
    ArrayList peps = new ArrayList();

    peps.add(new People(123, "M", 14.25));
    peps.add(new People(234, "M", 6.21));
    peps.add(new People(362, "F", 9.23));
    peps.add(new People(111, "M", 65.99));
    peps.add(new People(535, "F", 9.23));

    Collections.sort(peps);

    for(int i=0;i<peps.size();i++){
      System.out.println(peps.get(i));
    }
  }
}

I believe it has to do something with the casting in the compare method but I was playing around with it and still could not find the solution

+3  A: 

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


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

polygenelubricants
A: 

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.

Will Hartung
I forgot to mention this was homework, I was specifically told to use comparator
Dan
+2  A: 

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);
    }
}
Bart Kiers
The AgeComparator and similar comparisons of integers can be simplified to return `a.age - b.age`
Esko Luontola
@Esko: comparison-by-subtraction "trick" is broken for general `int` http://stackoverflow.com/questions/2728793/java-integer-what-is-faster-comparison-or-subtraction/
polygenelubricants
@Esko: because of what polygenelubricants mentioned, I simply always do it like that, even though for an age (which will not become very large) the subtraction like you mention would do.
Bart Kiers