Return first non empty list lazyily in Java 8

僤鯓⒐⒋嵵緔 提交于 2019-12-07 03:55:55

问题


I have N lists that return data from a Repository. I want to return the first non empty of these three lists (each one executes a different SQL to fetch data).

The catch is that I want to do this lazily, so that I don't need to execute a SQL on the database if I have already found an acceptable result. My code is (modified)

@Override
public List<Something> dataService(Data data) {

return firstNonEmptyList(repository.getDataWayOne(data.getParameter()), 
                         repository.getDataWayTwo(data.getParameter()),
                         repository.getDataWayThree(data.getParameter().getAcessoryParameter())
                         Collections.singletonList(repository.getDefaultData(data.getParameter()));

}

@SafeVarargs
private final List<Something> firstNonEmptyList(List<Something>... lists) {
for (List<Something> list : lists) {
  if (!list.isEmpty()) {
    return list;
  }
}

return null;

}

This works, but it isn't lazy. Any ideas?


回答1:


You can make a stream of suppliers and evaluate them in encounter order until you find a result:

return Stream.<Supplier<List<Something>>>of(
            () -> repository.getDataWayOne(data.getParameter()),
            () -> repository.getDataWayTwo(data.getParameter()),
            () -> repository.getDataWayThree(data.getParameter().getAcessoryParameter()),
            () -> Collections.singletonList(repository.getDefaultData(data.getParameter()))
        )
        .map(Supplier::get)
        .filter(l -> !l.isEmpty())
        .findFirst()
        .orElse(null);

Each supplier defines how to access a result set, without actually attempting it until map() is executed. Since filter() and map() are stateless operations, each supplier will be called and its result validated before the next one is attempted. If a non-empty result is found, the stream will terminate immediately, because findFirst() is short-circuiting.




回答2:


If streams aren't your cup of tea, you can still use lambdas to achieve what you want with only some slight modifications to your original code.

public List<Something> dataService(Data data) {
    return firstNonEmptyList(
            () -> repository.getDataWayOne(data.getParameter()),
            () -> repository.getDataWayTwo(data.getParameter()),
            () -> repository.getDataWayThree(data.getParameter().getAcessoryParameter()),
            () -> Collections.singletonList(repository.getDefaultData(data.getParameter()))
        );
}

private final List<Something> firstNonEmptyList(Supplier<List<Something>>... listSuppliers) {
    for (Supplier<List<Something>> supplier : listSuppliers) {
        List<Something> list = supplier.get();
        if (!list.isEmpty()) {
            return list;
        }
    }
    return null;
}


来源:https://stackoverflow.com/questions/42405656/return-first-non-empty-list-lazyily-in-java-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!