Krushna
Krushna

Reputation: 6060

Why I'm not getting a class cast exception or some thing else when adding element to TreeSet

The below is my code

class NumberComparator<Number> implements Comparator<Number> {
    public int compare(Number o1, Number o2) {
        return 1;
    }
}

public class Ex28 {
    public static void main(String[] args) {
        TreeSet set = new TreeSet(new NumberComparator<Number>());
        set.add(1);
        set.add(1.4f);
        set.add(1L);
        set.add("1a");
        System.out.println(set);
    }
}

As I have defined my own comparator of type Number , but still when I'm adding any thing else that is a string to it, it's not giving me any exception. It's simply working fine. I'm getting the output as

[1, 1.4, 1, 1a]

Can any one please explain why it's happening.

Upvotes: 10

Views: 621

Answers (3)

Vamsi Mohan Jayanti
Vamsi Mohan Jayanti

Reputation: 666

All said , you would get you class cast exception if you define your comparator as below :)

import java.util.Comparator;

class NumberComparator<Number> implements Comparator<java.lang.Number> {
public int compare(java.lang.Number o1, java.lang.Number o2) {


    return 1;
}
}

Upvotes: 0

adarshr
adarshr

Reputation: 62593

A Comparator for a TreeSet is used for ordering, not for throwing CCEs. Since your comparator is designed to return 1 for everything, it means that the ordering wouldn't be right.

That is the reason your output is not ordered.

Be sure to read the documentation of the constructor of TreeSet.

/**
 * Constructs a new, empty tree set, sorted according to the specified
 * comparator.  All elements inserted into the set must be <i>mutually
 * comparable</i> by the specified comparator: {@code comparator.compare(e1,
 * e2)} must not throw a {@code ClassCastException} for any elements
 * {@code e1} and {@code e2} in the set.  If the user attempts to add
 * an element to the set that violates this constraint, the
 * {@code add} call will throw a {@code ClassCastException}.
 *
 * @param comparator the comparator that will be used to order this set.
 *        If {@code null}, the {@linkplain Comparable natural
 *        ordering} of the elements will be used.
 */
public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}

It clearly states that if you try to add any other element other than the ones the Comparator is designed for, it would throw a ClassCastException. You could simulate this if you don't use generics by trying to add a String. If you do use generics, however, this would be just a compile time issue.

Meanwhile, you should be using generics consistently.

class NumberComparator<C> implements Comparator<C> {
    public int compare(C o1, C o2) {
        return 1; // change this logic
    }
}

Set<Number> set = new TreeSet<>(new NumberComparator<Number>());

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1500815

The problem is a mixture of some poor practices:

  • You're using the raw type for TreeSet
  • Your NumberComparator is generic (Number is a type parameter)

The fact that Number is a type parameter here means that type erasure means you won't actually be casting to the real Number type.

If you change your comparator to:

class NumberComparator implements Comparator<Number> {
    public int compare(Number o1, Number o2) {
        return 1;
    }
}

and your calling code to:

TreeSet set = new TreeSet(new NumberComparator());

then I'd expect an exception.

Further, if you change your code to not use the raw type:

TreeSet<Number> set = new TreeSet<Number>(new NumberComparator());

then you'll get a compile-time error instead.

Upvotes: 17

Related Questions