Search code examples
javagenericsguava

Comparator for Optional<T>


I have abstract class OptionalComparator<T extends Comparable<T>> implements Comparator<Optional<T>>

So far, so good.

Following the model used by Optional itself, I figured it would be best to have a single instance of this class, and cast it when necessary (for example, to OptionalComparator<Integer>).

So I made private static final OptionalComparator<? extends Comparable<?>> ABSENT_FIRST.

The trouble came when I tried to assign a value. What should the type be?

new OptionalComparator<Comparable<Object>>() {...} doesn't work.

new OptionalComparator<Comparable<Comparable<Object>>>() {...} doesn't work.

new OptionalComparator<Integer>() {...} does work, for example, but I want the least-specific type possible.

What am I doing wrong? How can I make a base-case instance of this class?


Solution

  • You can have multiple implementations of OptionalComparator like this:

    private static final OptionalComparator<? extends Comparable<?>> ABSENT_FIRST = new AbsentFirst<>();
    
    private static final OptionalComparator<? extends Comparable<?>> ABSENT_LAST = new AbsentLast<>();
    
    private interface OptionalComparator<T extends Comparable<T>> extends Comparator<Optional<T>> { }
    
    private static class AbsentFirst<T extends Comparable<T>> implements OptionalComparator<T> {
        @Override
        public int compare(Optional<T> obj1, Optional<T> obj2) {
            if (obj1.isPresent() && obj2.isPresent()) {
                return obj1.get().compareTo(obj2.get());
            } else if (obj1.isPresent()) {
                return -1;
            } else if (obj2.isPresent()) {
                return 1;
            } else {
                return 0;
            }
        }
    }
    
    private static class AbsentLast<T extends Comparable<T>> implements OptionalComparator<T> {
        @Override
        public int compare(Optional<T> obj1, Optional<T> obj2) {
            if (obj1.isPresent() && obj2.isPresent()) {
                return obj1.get().compareTo(obj2.get());
            } else if (obj1.isPresent()) {
                return 1;
            } else if (obj2.isPresent()) {
                return -1;
            } else {
                return 0;
            }
        }
    }
    
    static <T extends Comparable<T>> OptionalComparator<T> absentFirstComparator() {
        @SuppressWarnings("unchecked")
        OptionalComparator<T> comp = (OptionalComparator<T>) ABSENT_FIRST;
        return comp;
    }
    
    static <T extends Comparable<T>> OptionalComparator<T> absentLastComparator() {
        @SuppressWarnings("unchecked")
        OptionalComparator<T> comp = (OptionalComparator<T>) ABSENT_LAST;
        return comp;
    }
    
    public static void main(String... args) {
        OptionalComparator<Integer> absentFirstInt = absentFirstComparator();
        System.out.println(absentFirstInt.compare(Optional.of(1), Optional.empty()));
    
        OptionalComparator<Integer> absentLastInt = absentLastComparator();
        System.out.println(absentLastInt.compare(Optional.of(1), Optional.empty()));
    
        OptionalComparator<Double> absentFirstDouble = absentFirstComparator();
        System.out.println(absentFirstDouble.compare(Optional.of(1.0), Optional.empty()));
    
        OptionalComparator<Double> absentLastDouble = absentLastComparator();
        System.out.println(absentLastDouble.compare(Optional.of(1.0), Optional.empty()));
    }
    

    Output:

    -1
    1
    -1
    1