Reputation: 100
I would like to use a set of pairs in Java, but when I call contains()
to see if it already contains a specific pair then I always get a ClassCastException
. Is there a way to avoid this kind of behaviour?
It is instantiated like this:
private static final Set<Pair<String, String>> BLACKLIST = new TreeSet<>();
BLACKLIST.add(new Pair<String, String>("anytext", "anytext"));
Calling contains() here leads to following ClassCastException:
if (!blacklist.contains(new Pair<String, String>(localizedFile.getName(), key)))
java.lang.ClassCastException: .common.util.Pair cannot be cast to java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)
I use java.util classes instead of my own. Is there an elegant way to avoid to implement a new class pair which overloads common.util.Pair?
Upvotes: 0
Views: 336
Reputation: 1339
TreeSet uses the natuarl ordering of its elements unless you passed any explicit comparator to the constructor while creating the Set .
The contract says that all elements inserted into
the set must implement the Comparable interface.Furthermore, all such elements must be mutually comparable e1.compareTo(e2)
must not throw a
ClassCastException for any elements e1 and e2 in the set.
You code is
private static final Set<Pair<String, String>> BLACKLIST = new TreeSet<>();
BLACKLIST.add(new Pair<String, String>("anytext", "anytext"));
Since your have not passed a explicit Comparator to the constructor and neither your elements (Pair) implements a good Comparable you are getting a class cast exception while adding a element to the set.
My suggestion is (i) pass a explicit comparator
or(ii)make Pair implements Comparable as below
public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> implements Comparable<Pair<T1, T2>> {
T1 firstName;
T2 secondName;
public Pair(T1 firstName, T2 secondName) {
this.firstName = firstName;
this.secondName = secondName;
}
public T1 getFirstName() {
return firstName;
}
public T2 getSecondName() {
return secondName;
}
// elements ordered with first parameter .you can make a better
// comparable as well
@Override
public int compareTo(Pair<T1, T2> o) {
// TODO Auto-generated method stub
return this.firstName.compareTo(o.firstName);
}
}
Upvotes: 1
Reputation: 14999
TreeSet
uses the natural ordering of its elements, and it seems to cast to Comparable
to do that.
What you can do to make this code work is to give the TreeSet
your own Comparator
so it can use that instead of natural ordering.
Set<Pair<String, String>> blacklist = new TreeSet<>(
Comparator.comparing(Pair::getFirst)
.thenComparing(Pair::getSecond));
which will order by first, then second item of the Pair
.
Upvotes: 0