带有 if 子句的 Java 8 比较器

标签 java sorting lambda java-8 comparator

我想按日期对从数据库中获取的对象列表进行排序。问题是日期 (table1,table2) 的位置取决于 ObjectType。如果是 1,那么应该从第一个表中选择日期,如果是 2,则从第二个表中选择。我是这样开始的:

     objectList.stream().sorted((h1,h2)->
     if(h1.getObjectType().getId()==1){
     h1.getObject().getTable1().getTime()}//here is the problem
     );

但后来我感到困惑,因为在 if 子句之后我不能只添加 .compareTo。有什么方法可以使用带有 if 子句的 lambda 表达式来制作 Java 8 比较器?

最佳答案

这里同时发生了一些事情。

首先,如果你想使用 if-else在 lambda 内部的语句,你需要使用 lambda 语句(带大括号的那种)而不是 lambda 表达式(其中省略了大括号)。对于语句 lambda,您必须使用 return显式声明,而在表达式 lambda 中,返回值隐式地只是计算表达式的结果。

您有一些条件逻辑来选择要比较的值。我假设需要将此逻辑独立应用于要比较的两个对象中的每一个,因此这意味着直接的方法将需要您将逻辑写出两次。

最后,您需要编写一些实际比较的逻辑。

对于此示例,我假设要排序的对象的类型为 Obj并且它们被排序的值是 ObjDate 类型的我将进一步假设彼此具有可比性。 (即 ObjDate implements Comparable<ObjDate>。)我还将假设对象 ID 为 1 或 2,因此我不会处理值为其他值的情况。

这是一个使用语句 lambda 的完全写出的比较器:

    objectList.stream().sorted((h1, h2) -> {
        ObjDate h1date;
        ObjDate h2date;

        if (h1.getObjectType().getId() == 1) {
            h1date = h1.getObject().getTable1().getTime();
        } else {
            h1date = h1.getObject().getTable2().getTime();
        }

        if (h2.getObjectType().getId() == 1) {
            h2date = h2.getObject().getTable1().getTime();
        } else {
            h2date = h2.getObject().getTable2().getTime();
        }

        return h1date.compareTo(h2date);
    });

呃!编写比较器很有趣,不是吗? :-)

基本上,这个想法是应用 get-from-table1-or-table2 逻辑为第一个对象提取正确的值,然后对第二个对象进行同样的操作。最后返回比较结果。

这会起作用,但是这里有一些明显的重复代码。公共(public)代码可以称为键提取器,因为给定一个要比较的对象,它会提取用作比较基础的键。这是一个针对单个对象执行此操作的 key 提取器方法:

ObjDate getSortingDate(Obj obj) {
    if (obj.getObjectType().getId() == 1) {
        return obj.getObject().getTable1().getTime();
    } else {
        return obj.getObject().getTable2().getTime();
    }
}

现在我们有了这个,我们可以大大简化比较器:

    objectList.stream().sorted((h1, h2) -> {
        ObjDate h1date = getSortingDate(h1);
        ObjDate h2date = getSortingDate(h2);
        return h1date.compareTo(h2date);
    });

如果我们折叠局部变量,我们可以将其转换为表达式 lambda:

    objectList.stream().sorted(
        (h1, h2) -> getSortingDate(h1).compareTo(getSortingDate(h2)));

最后,从两个对象中提取键并比较它们的想法在比较器中非常普遍,因此有一个辅助方法可以为您完成此操作:Comparator.comparing(keyExtractor) .给定两个对象,这将在两个对象上运行 key 提取器并比较它们。 (更准确地说,它返回一个执行此操作的函数。)我们可以直接使用它来进一步简化事情:

    objectList.stream().sorted(Comparator.comparing(this::getSortingDate));

关于带有 if 子句的 Java 8 比较器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30177342/

相关文章:

Java Servlet 使用 HTML 表单创建 MySQL DB 并对其进行排序

python sort itemgetter等效于N维嵌套列表

haskell - 这个haskell函数中的这些值来自哪里?

使用 IF 语句的 Python 用户定义函数不起作用

java - Kafka 主题详细信息未在 Spark 中显示

perl - 对具有无序整数列的文件进行排序

java - CSRF token 验证失败,如何使用serenity放心框架修复?

c++ - lambda 返回 bool 值

Java Axis2 ExceptionInInitializerError Web 服务

java - 在java中将包括$cond的聚合转换为DBObject