Java 8 个带有 if 子句的比较器

Java 8 comparator with if clause

我想按日期对从数据库中获取的对象列表进行排序。问题是日期 (table1,table2) 的位置取决于 ObjectType。如果它是 1,那么应该从第一个 table 中选择日期,如果是 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 比较器?

由于有多行代码,您的 lambda 表达式中需要一个块。如果你的 lambda 中有一个块,你需要 return 一些东西。

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

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

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

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

对于这个例子,我假设被排序的对象是 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 逻辑为第一个对象提取正确的值,然后对第二个对象进行同样的操作。最后,return他们比较的结果。

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

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)。给定两个对象,这将在两个对象上运行密钥提取器并比较它们。 (更准确地说,它 return 是一个执行此操作的函数。)我们可以直接使用它来进一步简化事情:

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