Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 774
codebreaker Avatar asked Apr 10 '15 20:04

codebreaker


People also ask

What is optional <> in Java?

Optional is a container object used to contain not-null objects. Optional object is used to represent null with absent value. This class has various utility methods to facilitate code to handle values as 'available' or 'not available' instead of checking null values.

Why is Java optional 8?

So, to overcome this, Java 8 has introduced a new class Optional in java. util package. It can help in writing a neat code without using too many null checks. By using Optional, we can specify alternate values to return or alternate code to run.

Can we use compareTo in Comparator?

Java provides Comparable interface which should be implemented by any custom class if we want to use Arrays or Collections sorting methods. The Comparable interface has compareTo(T obj) method which is used by sorting methods, you can check any Wrapper, String or Date class to confirm this.

How do you get an object from optional?

Once you have created an Optional object, you can use the isPresent() method to check if it contains a non-null value. If it does, you can use the get() method to retrieve the value. Developers can also use the getOrElse() method, which will return the value if it is present, or a default value if it is not.


2 Answers

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
like image 149
Anderson Vieira Avatar answered Nov 23 '22 18:11

Anderson Vieira


Guava now provides (since 21.0, and no more @Beta since 27.1) Comparators.emptiesLast(Comparator) and emptiesFirst(Comparator).

Example: Comparator<Optional<Instant>> compareOptInst = Comparators.emptiesLast(Comparator.naturalOrder());

like image 22
Olivier Cailloux Avatar answered Nov 23 '22 19:11

Olivier Cailloux