带有if子句的Java 8比较器

Aly*_*ona 4 java sorting lambda comparator java-8

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

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

但后来我感到困惑,因为在if条款之后我不能只是添加.compareTo.有没有办法使用带有if子句的lambda表达式来制作Java 8比较器?

Stu*_*rks 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);
    });
Run Code Online (Sandbox Code Playgroud)

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

基本上,我们的想法是应用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    objectList.stream().sorted(
        (h1, h2) -> getSortingDate(h1).compareTo(getSortingDate(h2)));
Run Code Online (Sandbox Code Playgroud)

最后,从两个对象中提取密钥并比较它们的想法在比较器中是如此常见,以至于有一个辅助方法可以为您完成此任务:Comparator.comparing(keyExtractor).给定两个对象,它在两个对象上运行键提取器并比较它们.(更准确地说,它返回一个执行此操作的函数.)我们可以直接使用它来进一步简化:

    objectList.stream().sorted(Comparator.comparing(this::getSortingDate));
Run Code Online (Sandbox Code Playgroud)