Sort with one element at the end
List<Car> sortedCars = cars
.stream()
.sorted(Comparator.comparing(
Car::getName,
Comparator.comparing((String x) -> x.equals("Unassigned"))
.thenComparing(Comparator.naturalOrder())))
.collect(Collectors.toList());
There are a lot of things going on here. First I am using Comparator.comparing(Function, Comparator)
; then (String x) -> x.equals("Unassigned")
which actually compares a Boolean
(that is Comparable
); then the fact that (String x)
is used - as this type witness is used to correctly infer the types...
The most direct and and easy-to-read solution is probably to write a custom comparator that implements your sorting logic.
You can still use the Comparator.comparing
method to make it a bit prettier, though:
public static final String UNASSIGNED = "Unassigned";
List<Car> cars = List.of(
new Car("Unassigned"),
new Car("Nissan"),
new Car("Yamaha"),
new Car("Honda"));
List<Car> sortedCars = cars.stream()
.sorted(Comparator.comparing(Car::getName, (name1, name2) -> {
if (name1.equals(name2)) return 0;
if (name1.equals(UNASSIGNED)) return 1;
if (name2.equals(UNASSIGNED)) return -1;
return name1.compareTo(name2);
}))
.collect(toList());
It is possible to extract the "at-the-end" functionality to a separate comparable combinator method. Like this:
List<Car> sortedCars = cars.stream()
.sorted(Comparator.comparing(Car::getName, withValueAtEnd(UNASSIGNED)))
.collect(toList());
public static <T extends Comparable<T>> Comparator<T> withValueAtEnd(T atEnd) {
return withValueAtEnd(atEnd, Comparator.naturalOrder());
}
public static <T> Comparator<T> withValueAtEnd(T atEnd, Comparator<T> c) {
return (a, b) -> {
if (a.equals(atEnd)) return 1;
if (b.equals(atEnd)) return -1;
return c.compare(a, b);
};
}
Also, it's good style to use a named constant for special values like your "Unassigned"
.
Also, note that if you don't need to keep the unsorted cars
list, then you can sort that list in place instead of using a stream:
cars.sort(UNASSIGNED_COMPARATOR);
You could just replace "Unassigned" with an end-of-alphabet string in your comparator.
Comparator.comparing(car -> car.getName().equals("Unassigned") ? "ZZZ" : car.getName())