带有键提取器的Optional <T>的比较器,例如java.util.Comparator.comparing

乔治·Z:

考虑以下示例,其中我们根据人员的姓氏对其进行排序:

public class ComparatorsExample {

    public static class Person {
        private String lastName;

        public Person(String lastName) {
            this.lastName = lastName;
        }

        public String getLastName() {
            return lastName;
        }

        @Override
        public String toString() {
            return "Person: " + lastName;
        }
    }

    public static void main(String[] args) {
        Person p1 = new Person("Jackson");
        Person p2 = new Person("Stackoverflowed");
        Person p3 = new Person(null);
        List<Person> persons = Arrays.asList(p3, p2, p1);
        persons.sort(Comparator.comparing(Person::getLastName));
    }
}

现在,假设getLastName返回一个可选的:

public Optional<String> getLastName() {
    return Optional.ofNullable(lastName);
}

显然persons.sort(Comparator.comparing(Person::getLastName));不会编译,因为Optional(类型getLastName返回)不可比。但是,它拥有的价值是。

谷歌的第一个搜索为我们指出了这个答案根据此答案,我们可以通过以下方式对人员进行排序:

List<Person> persons = Arrays.asList(p3, p2, p1);
OptionalComparator<String> absentLastString = absentLastComparator(); //type unsafe
persons.sort((r1, r2) -> absentLastString.compare(r1.getLastName(), r2.getLastName()));

我的问题是,是否有可能像Comparator.comparing一样使用函数(键提取器)进行这种排序?

我的意思是(不关心第一个或最后一个缺少的值):

persons.sort(OptionalComparator.comparing(Person::getLastName));

如果查看Comparator.comparing,我们将看到以下代码:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable) (c1, c2) -> {
        return keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    };
}

我尝试了多种方法使它返回OptionalComparatora Comparator而不是简单的,但是我尝试过的所有有意义的事情都无法编译。甚至有可能实现这样的目标?我猜想类型安全性无法实现,因为甚至Oracle都comparing抛出了类型安全性警告。

我正在使用Java 8。

色拉:

您可以使用Comparator#comparing(Function,Comparator)

接受一个从类型中提取排序键的函数T,并返回一个Comparator<T>使用指定的键与该排序键进行比较的函数Comparator

这是一个基于您问题代码的示例:

persons.sort(comparing(Person::getLastName, comparing(Optional::get)));

基本上,这是使用嵌套键提取程序来最终比较String代表姓氏对象。请注意,NoSuchElementException如果其中一个Optional为空,则将引发a 您可以创建一个更复杂的方法Comparator来处理empty Optionals 1

// sort empty Optionals last
Comparator<Person> comp =
    comparing(
        Person::getLastName,
        comparing(opt -> opt.orElse(null), nullsLast(naturalOrder())));
persons.sort(comp);

如果需要大量执行此操作,请考虑以类似于Comparator#nullsFirst(Comparator)Comparator#nullsLast(Comparator)1的方式创建实用程序方法

// empty first, then sort by natural order of the value
public static <T extends Comparable<? super T>> Comparator<Optional<T>> emptyFirst() {
  return emptyFirst(Comparator.naturalOrder());
}

// empty first, then sort by the value as described by the given
// Comparator, where passing 'null' means all non-empty Optionals are equal
public static <T> Comparator<Optional<T>> emptyFirst(Comparator<? super T> comparator) {
  return Comparator.comparing(opt -> opt.orElse(null), Comparator.nullsFirst(comparator));
}

// empty last, then sort by natural order of the value
public static <T extends Comparable<? super T>> Comparator<Optional<T>> emptyLast() {
  return emptyLast(Comparator.naturalOrder());
}

// empty last, then sort by the value as described by the given
// Comparator, where passing 'null' means all non-empty Optionals are equal
public static <T> Comparator<Optional<T>> emptyLast(Comparator<? super T> comparator) {
  return Comparator.comparing(opt -> opt.orElse(null), Comparator.nullsLast(comparator));
}

然后可以这样使用:

persons.sort(comparing(Person::getLastName, emptyLast()));

1.根据@Holger提供的建议简化了示例代码如果有好奇的话,请看一下编辑历史,以查看代码之前的样子。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

NoSuchMethodError-没有静态方法比较(java / util / Comparator)

java.util.Comparator.naturalOrder采用<T扩展Comparable <?超级T >>并返回Comparator <T>-为什么?

Java的Comparator.comparing不是比较?

如何将以下比较器转换为Comparator.comparing?

使用Comparator.comparing(HashMap :: get)作为比较器时发生意外行为

Java 8:在基于给定键比较地图中的值时使用Comparator.comparing

java.util.Comparator实例的命名约定

Comparator.comparing()逆转()全部逆转早期比较?

比较是基于我自己的方法的结果时,如何使用Comparator.comparing()定义新的Comparator?

Java 8 中 Map.Entry 的 Comparator.comparing

Java Comparator.comparing方法中泛型的语义

Java 8中List的Comparator.comparing中的链方法

Java Comparator.comparing()类型签名是什么意思?

Scala 中 java.util.Comparator 的通用实现

嵌套场的Comparator.comparing(...)

Android的 - 是否有可能使用Comparator.comparing定制的比较,而不是原料药<24列表进行排序?

如何使用Comparator.comparing()比较字符串作为双?

在 Java 中如何为扩展 Comparator 的类实现多个比较器方法?

带有迭代器的java.util.ConcurrentModificationException

为什么Java 8的Comparator.comparing()将返回值转换为Serializable?

Java Integer 类是否有返回 Comparator 的比较方法?

“java:找不到适合 sort(java.util.ArrayList<Person>,<匿名 java.util.Comparator<Person>>) 的方法”

Comparator.comparing中的多次检查

Java java.util.Map.Entry和Collection.sort(List,Comparator)

为什么equals在java.util.Comparator中不是必须实现的?

“ java.util.Comparator.compare(String o1,String o2)”方法的工作原理

Eclipse的Content Assist不适用于java.util.Comparator

实现接口 Comparator<T>

可选<T>的比较器