问题
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