Comparator for Optional<T>

我是研究僧i 提交于 2020-07-06 11:25:34

问题


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?


回答1:


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



回答2:


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());




回答3:


You may just have to do an unsafe cast. Consider how ImmutableList handles the empty-list case:

private static final ImmutableList<Object> EMPTY =
    new RegularImmutableList<Object>(ObjectArrays.EMPTY_ARRAY);

/**
 * Returns the empty immutable list. This set behaves and performs comparably
 * to {@link Collections#emptyList}, and is preferable mainly for consistency
 * and maintainability of your code.
 */
// Casting to any type is safe because the list will never hold any elements.
@SuppressWarnings("unchecked")
public static <E> ImmutableList<E> of() {
  return (ImmutableList<E>) EMPTY;
}

In this case, it might similarly be easiest to use a raw type instance. As long as you gate all calls that return ABSENT_FIRST with generic casts, this will be fine, and calling code shouldn't have any warnings.



来源:https://stackoverflow.com/questions/29570118/comparator-for-optionalt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!