简体   繁体   English

Java 流; 避免在 Collectors.collectingAndThen 上完成终结者

[英]Java Streams; avoid finisher on Collectors.collectingAndThen

I've this code:我有这个代码:


private Iterable<Practitioner> pickPractitioners(List<String> ids) {

    return Optional.ofNullable(ids)
        .map(List::stream)
        .orElse(Stream.of())
        .collect(
            Collectors.collectingAndThen(
                Collectors.toList(),
                this.practitionerRepository::findAllById
            )
        );

}

Problem is that when ids is empty, this.practitionerRepository::findAllById is also executed.问题是当ids为空时, this.practitionerRepository::findAllById也会被执行。

I'd like to avoid this step if resulting collector is empty.如果结果收集器为空,我想避免这一步。

Any ideas?有任何想法吗?

In general to skip that part of the finisher you could pass a lambda instead of a method reference and check if the input is empty:通常,要跳过完成器的那部分,您可以传递 lambda 而不是方法引用并检查输入是否为空:

    .collect(
        Collectors.collectingAndThen(
            Collectors.toList(),
            r -> r.isEmpty() ? Collections.emptyList() : this.practitionerRepository.findAllById(r)
        )
    );

If your actual code is a simple as this example then you don't need to use streams or optional at all.如果您的实际代码像此示例一样简单,那么您根本不需要使用流或可选代码。 Instead you could just check if the input of the method is null or empty in a ternary operator:相反,您可以检查方法的输入是 null 还是在三元运算符中为空:

    return ids == null || ids.isEmpty() ? Collections.emptyList() :
        this.practitionerRepository.findAllById(ids);

If you look at the signature of the Finisher.如果您查看 Finisher 的签名。 It is just a function, so you can just write it:它只是一个 function,所以你可以写它:

 public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) {
static interface MyRepository extends JpaRepository<Part, Long> {

}

public static void main(String[] args) {

    MyRepository myRepository = null;
    List<Long> list = null;

    Function<List<Long>, List<Part>> finisher = (ids) -> {

        return ids.isEmpty() ? Collections.emptyList() : myRepository.findAllById(ids);

    };

    Optional.ofNullable(list)
            .map(List::stream)
            .orElse(Stream.of())
            .collect(
                    Collectors.collectingAndThen(
                            Collectors.toList(),
                            finisher
                    )
            );

}

Whilst the practical part of this question ( how to avoid interrogating the repository with an empty list as an argument ) is already addressed in other answers I want to point out that there's a cleaner way to build a pipeline in this method.虽然这个问题的实际部分( how to avoid interrogating the repository with an empty list as an argument )已经在其他答案中得到解决,但我想指出,在这种方法中构建管道有一种更简洁的方法。

Firstly it's worthy to remind that the main purpose of Optional.ofNullable() is to create an Optional object that has to be returned from a method .首先值得提醒的是, Optional.ofNullable()的主要目的是创建一个必须returned from a method的 Optional object 。

Attempts to use Optional.ofNullable() in order to utilize method-chaining or to avoid null-checks in the middle of the method according to Stuart Marks are considered to be anti-patterns.根据Stuart Marks ,尝试使用Optional.ofNullable()以利用方法链接或避免在方法中间进行空检查被认为是反模式。

Here is the quote from his talk at Devoxx :以下是他在 Devoxx 演讲中的引述:

"it's generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value." “为了从其中链接方法以获取值的特定目的而创建 Optional 通常是一个坏主意。”

A similar idea was expressed in his answer on stackoverflow .在他answer on stackoverflow中表达了类似的想法。

What are the alternatives?有哪些替代方案?

Since Java 9 Stream interface has its own method ofNullable() .由于 Java 9 Stream interface有自己的方法ofNullable()

Returns a sequential Stream containing a single element, if non-null, otherwise returns an empty Stream.如果非空,则返回包含单个元素的顺序 Stream,否则返回空 Stream。

Kipping all that in mind method pickPractitioners() could be rewritten like this:记住所有这些方法pickPractitioners()可以这样重写:

private Function<List<String>, Iterable<Practitioner>> getPractitioners =
        idList -> idList.isEmpty() ? Collections.emptyList() : 
                                     this.practitionerRepository.findAllById(idList);


private Iterable<Practitioner> pickPractitioners(List<String> ids) {

    return Stream.ofNullable(ids)
            .flatMap(List::stream)
            .collect(Collectors.collectingAndThen(
                            Collectors.toList(),
                            getPractitioners
            ));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 具有泛型流的Java 8收集器 - java 8 collectors for streams with generics 将多个 `Collectors::groupBy` 函数与 Java Streams 结合使用 - Combine multiple `Collectors::groupBy` functions with Java Streams .collect(Collectors.toList())和Java方法上的Streams - .collect(Collectors.toList()) and Streams on Java Method 将CollectingAndThen()与Collectors.toMap()结合使用需要显式类型转换 - Using collectingAndThen() with Collectors.toMap() requires explicit type cast Java,Streams:如何使用.collect(Collectors.toList())转换表达式 - Java, Streams: how to convert expression with.collect(Collectors.toList()) Java8 流收集器.ToMap 方法引用失败 - Java8 streams collectors.ToMap Method reference failing Java Streams:使用 Collectors.toCollection 将返回集合修改为自定义类型 - Java Streams: modifying return collection to a custom type with Collectors.toCollection Java 8使用流和收集器映射到集合的子列表条目 - Java 8 mapping to sub list entries of a collection using streams and collectors 使用Java 8的流和收集器将Collection转换为Map转换到方法中 - Encapsulating Collection to Map transformation using Java 8's streams and collectors into a method Java 8 个流 - 在 Collectors.groupingBy 中处理空值 - Java 8 Streams - Handle Nulls inside Collectors.groupingBy
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM