saba
saba

Reputation: 539

Geting Error For Generic Chained Comparator

Before asking this question I want to say I am new in Java Generics. I have tried to implement Comparator chaining for a class so I have created this following class.

    static class ChainComparator implements Comparator<StudentDTO> {
    
    List<Comparator<StudentDTO>> chainComparators;

    @SafeVarargs
    public ChainComparator(Comparator<StudentDTO>... comparators) {
        chainComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(StudentDTO o1, StudentDTO o2) {
        for (Comparator<StudentDTO> comparator : chainComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

Here this class I have created for multiple comparator implementation for Student class. Now I am thinking this can be generic for all classes so I have tried with the following class.

public class ChainComparator implements Comparator<Class<?>>{
    List<Comparator<?>> chainComparators;

    @SafeVarargs
    public ChainComparator(Comparator<?>... comparators) {
        chainComparators = Arrays.asList(comparators);
    }
    @Override
    public int compare(Class<?> o1, Class<?> o2) {
        for (Comparator<?> comparator : chainComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

But here I am getting the following compilation error

The method compare(capture#1-of ?, capture#1-of ?) in the type Comparator<capture#1-of ?> is not applicable for the arguments (Class<capture#2-of ?>, Class<capture#3-of ?>)

I am getting this above error on the below line

comparator.compare(o1, o2);

Can anyone please help me to understand why I am getting this error and how I can solve this error or my approach itself is wrong.

I can understand if I use any other library or Java8 I can achieve this very quickly with a decent code but actually I just curious and wanted to learn and understand Generic more.

Upvotes: 0

Views: 73

Answers (1)

Andreas
Andreas

Reputation: 159086

You can't use wildcards here, because every wildcard is independent of the others.

Comparator<?> and compare(Class<?> o1, Class<?> o2) can be considered as meaning Comparator<A> and compare(Class<B> o1, Class<C> o2), where A, B, and C can each be anything (wildcard), but you cannot of cause compare a Class<B> with a Class<C>.

What you need to do is declare a generic parameter.

static class ChainComparator<T> implements Comparator<T> {
    
    List<Comparator<T>> chainComparators;

    @SafeVarargs
    public ChainComparator(Comparator<T>... comparators) {
        chainComparators = Arrays.asList(comparators);
    }

    @Override
    public int compare(T o1, T o2) {
        for (Comparator<T> comparator : chainComparators) {
            int result = comparator.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

You would then use it using the diamond operator:

Comparator<Foo> chain = new ChainComparator<>(fooComparator1, fooComparator2);

Upvotes: 1

Related Questions