How do I implement a Comparator using Generics? - java

Just a minor problem with Arraylist. I want to sort a ArrayList<Client> by name.
Class Client{ String name; int phonenumber ..}
This code does the work, but i'm having a compiler warning: "uses unchecked or unsafe operations". Whats the problem?
public void sortByName(){
Collections.sort(ListofClients, new NameComparator());
}
My comparator looks like this:
public class NameComparator implements Comparator{
public int compare(Object client1, Object client) {
String name1 = ((Client) client1).getName();
String name2 = ((Client) client2).getName();
return name1.toUpperCase()).compareTo(name2.toUpperCase();
}
}
If i use "implements Comparator<Client> " i get a error: "NameComparator is not a abstract and does not override abstract method compare(Client, Client) in java.util.Comparator. Is my comparator wrong? sorry for this noob question, new to java

After you implement Comparator<Client> you need to change:
public int compare(Object client1, Object client)
{
...
}
to this
public int compare(Client client1, Client client)
{
// Now you don't have to cast your objects!
}
this is all because the definition of comparator
public interface Comparator<T>
{
public compare(T o1, T o2);
}
Notice how the generic parameter T shows up in the method name.
An IDE like Eclipse / Netbeans / IntelliJ will help out in this situation.

I presume your list of clients is of the type
List<Client>
in which case your comparator should be of type Comparator<Client>, and perform the appropriate comparison (by name, in this case)

Related

Declaring generics

I have a problem with defining generics in static methods and fields.
Suppose I have a simple interface, used by all classes that contains a field of type T called value:
public interface HasValue<T> {
// Getter:
public T value();
// Setter:
public void setValue(T value);
}
If I have an array of object of a type N that implements HasValue<T>, I may have necessity to order this array. One classical way is to compare those N objects using their value field: if T implements the Comparable<T> interface and both arg0 and arg1 are of type N, then arg0.compareTo(arg1) will be equal to arg0.value().compareTo(arg1.value()).
The goal is to create a usable, not time-consuming, possible simple way to obtain the aforementioned situation.
A possibility would be to create a custom Comparator<N> every time I need something similar. That would force me to write code each time: definitly time consuming.
I could create that Comparator<N> directly in the interface. The first try is to create a method:
It needs to be a default method. Part of the code will test if the class T implements the Comparable interface or not, and for that I need an example of the T class: using this.value().getClass() is the fastest way. With a static method I could not use this.
I need to explicitate that the N class implements the interface HasValue<T>, otherwise the computer will not know.
public default <N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE() throws Exception{
if(Comparable.class.isAssignableFrom(this.value().getClass()))
return new Comparator<N>() {
public int compare(N arg0, N arg1) {
Comparable value0 = (Comparable) arg0.value(),
value1 = (Comparable) arg1.value();
return value0.compareTo(value1);
}
};
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
This strategy works... barely. It's clumsy, involves rawtypes, creates the Comparator<N> every time.
Second try: creating a static field.
The strategy is to separate the testing problem from the rest. A default method will do the test: in case of success the method will return a static Comparator, otherwise an exception.
public default <N extends HasValue<T>> Comparator<?> COMPARE_BY_VALUE() throws Exception{
if(Comparable.class.isAssignableFrom(this.value().getClass()))
return COMPARE_BY_VALUE;
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
public static Comparator<HasValue> COMPARE_BY_VALUE = new Comparator() {
public int compare(Object arg0, Object arg1) {
Comparable value0 = (Comparable) ((HasValue)arg0).value(),
value1 = (Comparable) ((HasValue)arg1).value();
return value0.compareTo(value1);
}
};
While declaring the static field I (unfortunately) cannot state something like public static <T, N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE. That forces me to return a Comparator<HasValue>: not what I wanted.
Using wildcards I can obtain something close:
public default <N extends HasValue<T>> Comparator<?> COMPARE_BY_VALUE() throws Exception{
if(Confrontable.class.isAssignableFrom(this.value().getClass()))
return COMPARE_BY_VALUE;
else throw new Exception("The class of the value does not implement the interface Comparable.\n");
}
public static Comparator<? extends HasValue<? extends Comparable<?>>> COMPARE_BY_VALUE
= new Comparator() {
public int compare(Object arg0, Object arg1) {
Comparable value0 = (Confrontable) ((HasValue<?>)arg0).value(), value1 = (Confrontable) ((HasValue<?>)arg1).value();
return value0.compareTo(value1);
}
};
This modification will return (in theory) a Comparator<N> where N extends HasValue<T>, T extends Comparable<U> and U is actually T.
That because every ? in Comparator<? extends HasValue<? extends Comparable<?>>> is interpreted by the JVM as a potential new class: three ? means three new class (N, T and U), and it happens that T implements Comparable<T> - thus U and T are one and the same.
I still have a great amount of rawtypes...
...but at least I have only one Comparator for each N and T.
Now, while the last strategy seems to works, I would like to know if there is a better way to obtain my goal.
My initial idea was to state something like
public static <T extends Comparable<T>, N extends HasValue<T>> Comparator<N> COMPARE_BY_VALUE = new Comparator() {
public int compare(N arg0, N arg1) {
return arg0.value().compareTo(arg1.value());
}
};
and obtain a Comparator<N> without wildcars. This however sends all types of errors. Someone has an idea?
Just do:
static <T extends Comparable<T>> Comparator<HasValue<T>> createValueComparator() {
return new Comparator<HasValue<T>>() {
#Override
public int compare(HasValue<T> o1, HasValue<T> o2) {
return o1.value().compareTo(o2.value());
}
};
}
This reads: for every type T which implements Comparable this method returns comparator which can compare HasValue<T>.
Java might not be able to properly infer types in such convoluted constructs. You might have to add the types explicitly:
Collections.sort(list, Main.<Integer> createValueComparator());
or:
Comparator<HasValue<Integer>> comparator = createValueComparator();
Collections.sort(list, comparator);
Keep in mind that a lot of programmers overuse generics. Usually there is a simpler way to achieve the same - while still maintaining type safety.

Java using Comparator

I am implementing Comparator and Comparable in my class Employee to sort an arraylist. I am sorting on 2 parameters name and ID. While sorting with ID using Collections.sort(Employee ob1, Employee ob2) it doesn't work. I get the compilation error that the class is not declared abstact and i am not overriding compare(), although i am doing it as:
public int compare(Employee ob1, Employee ob2)
{
return ob1.id-ob2.id;
}
it works fine if i use
public int compare(Object ob1, Object ob2)
{
return ((Employee)ob1).id-((Employee)ob2).id;
}
My doubt is why does't the earlier one work since Employee is also an Object.
The same issue is with compareTo(Object ob) as well, While overriding why can't i use Employee directly and why do i need to use Object there and later need to cast it to Employee class.
Polymorphism, using Object, Object overrides a raw-type in Comparator. Using your class names doesn't match that signature. For a compile error when you mix up the signature use the template type.
public class Employee implements Comparator<Employee> {
// ....
#Override
public int compare(Employee ob1, Employee ob2) {
return ob1.id-ob2.id;
}
}
You need to implement the exact methode the interface defines.
If you want to work directly with your Object use the <> generic syntax:
public class Employee implements Comparator<Employee>
{
#Override
public int compare(Employee ob1, Employee ob2)
{
return ob1.id - ob2.id;
}
}
Make sure to use the #Override Annotation. This will give you a compiler warning if you get the methode wrong (parameter, return values etc.)
When using Comparable you can use it like this:
public class Employee implements Comparable<Employee>
{
#Override
public int compareTo(Employee e)
{
//your compare code
}
}
See also: Comparable vs Comparator

What's alternative NSSortDescriptor in Java?

I hava ArrayList which is include Custom Data Class.
ArrayList<MyData> list
Custom Data class has several field
class MyData {
private int num;
private String name;
etc....
getter/setter...
}
I want to sort List by field (ex:num)
Objecitive-C has NSSortDescriptor which can sort objects.
NSSortDescriptor Class Reference
is There alternative this? or other solution?
You can use Comparable and Comparator interface.. and the use Collection.sort().
You need to implement Comparable and Comparator interface, if you are using Collection of Custom Type(i.e not primitive types).
For detailed examples check http://www.mkyong.com/java/java-object-sorting-example-comparable-and-comparator/
Hope this post will be helpful to u.
Implement Comparable or Comparator and use Collections.sort().
Comparable
public class MyClass implements Comparable<MyClass>{
public int x;
public int compareTo(MyClass mc){
return x - mc.x;
}
}
Comparator
public class MyClass{
public int x;
}
public class MyClassComparator implements Comparator<MyClass>{
public int compare(MyClass mc1, MyClass mc2){
return mc1.x - mc2.x;
}
}
java.util.Comparator coupled with java.util.Collection.sort should do the trick.
You could also have MyData implement java.util.Comparable and use the other sort method, but that isn't quite as flexible.
There is nothing similar to NSSortDescriptor in Java: Java sorting uses the style that is more similar to the sortUsingComparator: method of the NSMutableArray class:
Collections.sort(list, new Comparator<MyData>() {
// This is similar to the comparator block of Cocoa
public int compare(MyData o1, MyData o2) {
// Put the comparison code here
...
}
});

converting Comparable from and to Comparator?

I often have a Comparator type while I need a Comparable and the other way around. Is there a reusable JDK API to convert from one another? Something along the lines of:
public static <C> Comparable<C> toComparable(final Comparator<C> comparator) {
// does not compile because Hidden can not extend C,
// but just to illustrate the idea
final class Hidden extends C implements Comparable<C> {
#Override
public int compareTo(C another) {
return comparator.compare((C) this, another);
}
};
return new Hidden();
}
public static <C extends Comparable<C>> Comparator<C> toComparator(final Class<C> comparableClass) {
return new Comparator<C>() {
#Override
public int compare(C first, C second) {
assert comparableClass.equals(first.getClass());
assert comparableClass.equals(second.getClass());
return first.compareTo(second);
}
};
}
ComparableComparator from Apache Commons Collections seems to address Comparable<T> to Comparator problem (unfortunately its not generic type-friendly).
The reverse operation is not quite possible because the Comparator<T> represents algorithm while Comparable<T> represents actual data. You will need composition of some sort. Quick and dirty solution:
class ComparableFromComparator<T> implements Comparable<T> {
private final Comparator<T> comparator;
private final T instance;
public ComparableFromComparator(Comparator<T> comparator, T instance) {
this.comparator = comparator;
this.instance = instance;
}
#Override
public int compareTo(T o) {
return comparator.compare(instance, o);
}
public T getInstance() {
return instance;
}
}
Say you have class Foo that is not Comparable<Foo> but you have Comparator<Foo>. You use it like this:
Comparable<Foo> comparable = new ComparableFromComparator<Foo>(foo, comparator);
As you can see (especially without mixins) it's pretty ugly (and I'm not even sure if it'll work...) Also notice that comparable doesn't extend Foo, you have to call .getInstance() instead.
Since Java 8 the Comparator interface has had a few utility default methods added that assist with deriving a comparator from a comparable.
Consider the following example of sorting users by first name.
class Person {
String firstName;
String lastName;
}
List<Person> people = ...
people.sort(Comparator.comparing(Person::firstName));
You can obtain an instance of Comparator able to compare instance of Comparable type simply with
java.util.Comparator.naturalOrder()
see Comparator.naturalOrder()
this is a sort of conversion from Comparable to Comparator
Comparable items can be sorted as they have a compareTo:
Collection<Comparable> items;
Collections.sort(items);
If items are not Comparable, they need a Comparator object to do the comparison:
Collections<T> items;
Collections.sort(items, comparator);
A bridging Comparator is trivial, and you did it already.
Wrapping every T item with some Comparable adapter having a Comparator, seems useless.
First of all not inheritance but as field one needs to wrap the item.
public class CatorComparable<T> implements Comparable<CatorComparable<T>> {
public T value;
private Comparator<T> cator;
public CatorComparable(T value, Comparator<T> cator) {
this.value = value;
this.cator = cator;
}
#Override
public int compareTo(CatorComparable<T> other) {
return cator.compareTo(value, other.value);
}
}
Too much overhead.
I don't think you can really convert between them, nor does it really make sense to, since Comarable is a property of the class itself, while Comparator is an external class.
The best bet would be to write some sort of utility class that contains the underlying comparison logic (and probably have that implement Comparator), then use that class as a part of the logic for the Comparable implementation on the class itself.

Sorting problem cannot instantiate abstract object overriding compareTo() Method

I'm trying to establish a new sort criteria, in this case by name.
I'm facing an error when I call the sort method...
this is a separated class (SortByName) in package "package":
-----------------------CLASS SortByName---------------------------
package package;
import java.util.*;
public abstract class SortByName implements Comparator{
public int compareTo(Object o1, Object o2){
String n1 = ((Ficha)o1).getName();
String n2 = ((Ficha)o2).getName();
return n1.compareTo(n2);
}
and then inside an ActionPerformed event I have this:
----------------IN THE ACTION EVENT BUTTON----------------------------
Collections.sort( list , new SortByName() );
"package.SortByName is abstract,> cannot be instantiated"
I tried changing the "abstract" type in the class definition (SortByName) , but it complies about not overriding the compareTo() method.
thanks for reading.
The method you have to implement is called compare, not compareTo.
Abstract classes cannot be instantiated.
Also, Comparator is generic, so you'd better do the following:
public class SortByName implements Comparator<Ficha>{
public int compareTo(Ficha f1, Ficha f2){
String n1 = f1.getName();
String n2 = f2.getName();
return n1.compareTo(n2);
}
}
Comparator needs to implement compare(), not compareTo() method.
class SortByName implements Comparator<Ficha>{
#Override
public int compare(Ficha o1, Ficha o2) {
String n1 = o1.getName();
String n2 = o2.getName();
return n1.compareTo(n2);
}
}
You need to remove "abstract" and implement the equals method as well.
Code should look like:
package package;
import java.util.*;
public class SortByName implements Comparator{
public int compare(Object o1, Object o2){
String n1 = ((Ficha)o1).getName();
String n2 = ((Ficha)o2).getName();
return n1.compareTo(n2);
}
public boolean equals(Object o1) {
// code which compares the current comparator (!) with the object given
}
Note that you might need to use specialized comparators if compiling against a version of java which supports generics. Not sure if this is correct but I think you can do something like:
public class SortByName implements Comparator <Ficha> {
public int compare(Ficha o1, Ficha o2){
// comparing code here
}
}
But again, not entirely sure on that part, you need to test it a bit.
If you check out the Comparator API that will explain how you must implement equals.
Also note that the Comparator interface defines compare, not compareTo.
Laura you were right I had to add the equals method.( u missed the return value)
also remove "abstract" at class definition.
and change compareTo() with compare().
thanks a lot Laura, PROBLEM SOLVED !!!!

Categories