带有if子句的Java 8比较器

时间:2015-05-11 20:45:49

标签: 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比较器?

2 个答案:

答案 0 :(得分:8)

这里有一些事情在发生。

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

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

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

对于此示例,我假设正在排序的对象属于Obj类型,并且他们要对其进行排序的值属于ObjDate类型,而我{&#39}。进一步假设彼此相当。 (也就是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逻辑为第一个对象提取正确的值,然后对第二个对象提取相同的值。最后,返回比较它们的结果。

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

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

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

答案 1 :(得分:0)

由于有多行代码,因此在lambda表达式中需要一个块。如果你的lambda中有一个块,你需要返回一些东西。