我试图用Java Lambda Expresions替换现有循环。

我有一个简单的数据结构,如下所示:

class DbObject{
    private Long objectId;

    private Long basedOnObjectId; //<- this field can be null

    public Long getObjectId() {
        return objectId;
    }

    public void setObjectId(Long objectId) {
        this.objectId = objectId;
    }

    public Long getBasedOnObjectId() {
        return basedOnObjectId;
    }

    public void setBasedOnObjectId(Long basedOnObjectId) {
        this.basedOnObjectId = basedOnObjectId;
    }
}


然后我有一个DbObjects列表

我试图用指定的basedOnObjectId筛选每个DbObject:

(1) list.stream().filter(object -> obejct.getBasedOnObjectId()
             .equals(basedOnObject.getObjectId()))
             .collect(Collector.of(List))


当然,这段代码为我提供了NullPointer,因为某些od DbObject因为它们是根而没有BasedOnObjectId。

很自然的事情是替换字段“ Long basedOnObjectId;”通过可选,但是正如我在开始时提到的那样,现有的生产代码无法快速解决。

因此,我尝试进行一些更改,我评估以下句子:

 Optional<Long> option = Optional.ofNullable(objectWithNullBasedOnId.getBasedOnObjectId());


并尝试使用.get()方法或.ifPresent(),但.get()还会引发空指针异常,并且ifPresent不专用于处理流。

我注意到了这样的事实,即当我将DbObject的值设置为null basedOnObjectId时,我不必检查value是否恰好为null,而只需跳过此执行步骤。

因此,我决定使用.orElse()方法并返回一些假值。在这种情况下,我返回0L值,因为该索引在DB中不存在:)

所以我的代码:

 (2) List newList = list.stream().filter(object -> Optional.ofNullable(object.getBasedOnObjectId())
                             .orElse(0L)
                             .equals(basedOnObject.getObjectId()) )
                             .collect(Collectors.toList()) ;


在这种情况下,这种方法可以正常工作,但是我认为这是一种解决方法。在其他语言中,可以使用空值跳过执行,也可以使用诸如skip-skipWhen方法之类的方法。

我的问题是:是否有可能使用java 8中的专用方法(例如Optional)达到(2)表达式的目标并编写“ in stream style” :)

最佳答案

如果比较Optional<Long>而不是Long,则无需区分当前对象和不存在对象。

Optional<Long> root = Optional.of(basedOnObject.getObjectId());
list.stream()
    .map(DbObject::getBasedOnObjectId)
    .map(Optional::ofNullable)
    .filter(root::equals)
    .collect(Collectors.toList());


在这种情况下,它甚至更简单,因为您可以反转比较:

list.stream()
    .filter(o -> basedOnObject.getObjectId().equals(o.getBasedOnObjectId()))
    .collect(Collectors.toList());

09-25 15:04