Java Stream: 如何有条件地筛选?

huangapple go评论52阅读模式
英文:

Java Stream : How to filter conditionally?

问题

I have the following stream statement with Java Stream and I filter records based on the typeId values as types.getIds().contains(x.getType().getId()):

return petRepository.findAll().stream()
                .filter(x -> types.getIds().contains(x.getType().getId()))
                .collect(Collectors.groupingBy(x -> x.getType().getName(), Collectors.counting()));

However, I want to fetch all values when types.getIds().size() == 0 and tried something as shown below:

.filter(types.getIds().size() > 0 ? x -> types.getIds().contains(x.getType().getId()) : <NO FILTERING>)

So, how can I skip filtering when types.getIds().size() == 0?

英文:

I have the following stream statement with Java Stream and I filter records based on the typeId values as types.getIds().contains(x.getType().getId()):

return petRepository.findAll().stream()
                .filter(x -&gt; types.getIds().contains(x.getType().getId()))
                .collect(Collectors.groupingBy(x -&gt; x.getType().getName(), Collectors.counting()));

However, I want to fetch all values when types.getIds().size() == 0 and tried something as shpon below:

.filter(types.getIds().size() &gt; 0 ? x -&gt; types.getIds().contains(x.getType().getId()) : &lt;NO FILTERING&gt;)

So, how can I skip filtering when types.getIds().size() == 0 ?

答案1

得分: 5

如果您不想在每个 `x` 上检查是否为空,您可以将整个 lambda 放在一个三元表达式中:

    return petRepository.findAll().stream()
                .filter(types.getIds().isEmpty() ? x -> true 
                        : x -> types.getIds().contains(x.getType().getId()))
                .collect(Collectors.groupingBy(x -> x.getType().getName(), Collectors.counting()));

或者将流放入临时变量中,有条件地应用整个 `filter()`:

    Stream<X> stream = petRepository.findAll().stream();
    if (!types.getIds().isEmpty()) {
        stream = stream.filter(x -> types.getIds().contains(x.getType().getId()));
    }
    return stream.collect(Collectors.groupingBy(x -> x.getType().getName(), Collectors.counting()));
英文:

If you don't want to check for empty on every x, you can put the whole lambda in a ternary expression:

return petRepository.findAll().stream()
            .filter(types.getIds().isEmpty() ? x -&gt; true 
                    : x -&gt; types.getIds().contains(x.getType().getId()))
            .collect(Collectors.groupingBy(x -&gt; x.getType().getName(), Collectors.counting()));

Or pop the stream in a temporary variable and apply the entire filter() conditionally:

Stream&lt;X&gt; stream = petRepository.findAll().stream();
if (!types.getIds().isEmpty()) {
    stream = stream.filter(x -&gt; types.getIds().contains(x.getType().getId()));
}
return stream.collect(Collectors.groupingBy(x -&gt; x.getType().getName(), Collectors.counting()));

答案2

得分: 2

请记住,在filter中的谓词必须在您希望包含结果时返回true。所以在您的情况下,筛选条件必须是这样的,如果ids不为空,那么筛选条件只有在您希望的条件下才会返回true。如果ids为空,那么筛选必须始终返回true。

您可以通过编写一个最小的测试示例(最好是使用junit或另一个测试框架模拟您的petRepository)来进行测试。

考虑以下示例:

Set<Integer> ids = Set.of(2);
List<Integer> elements = List.of(1, 2, 3);
List<Integer> list = elements.stream()
        .filter(u -> ids.size() > 0 ? ids.contains(u) : true)
        .toList();
System.out.println(list);

// 输出将是[2]
// 但如果ids为空,输出将是[1, 2, 3]

请注意filter中的条件:ids.size() > 0 ? ids.contains(u) : true

如果有要检查的ids,请查看elements的流式元素是否包含在其中。如果没有要检查的ids,无论如何都返回true(保留元素流中的所有内容以进行管道中的下一步操作)。

在这种情况下,三元表达式可以进一步简化为u -> ids.size() <= 0 || ids.contains(u)

英文:

You just need to remember that the predicate in the filter has to return true whenever you want a result to be included. So in your case the filter condition must be such that, if the ids are NOT empty, filter will only return true for the condition you want. If the ids are empty, then filter must always return true.

You can play with this by writing a minimal test example (or better yet, mocking your petRepository with junit or another testing framework).

Consider:

Set&lt;Integer&gt; ids = Set.of(2);
List&lt;Integer&gt; elements = List.of(1, 2, 3);
List&lt;Integer&gt; list = elements.stream()
        .filter(u -&gt; ids.size() &gt; 0 ? ids.contains(u) : true)
        .toList();
System.out.println(list);

// output here will be [2]
// but if ids is empty it will be [1, 2, 3]

Look at what's inside filter: ids.size() &gt; 0 ? ids.contains(u) : true

If there are ids to check, see if the streamed element of elements is contained in them. If there are no ids to check, return true regardless (keep everything in the elements stream for the next step in the pipeline).

The ternary expression in this case could be further simplified to u -&gt; ids.size() &lt;= 0 || ids.contains(u).

答案3

得分: 1

return petRepository.findAll().stream()
.filter(x -> types.getIds().isEmpty() ||
types.getIds().contains(x.getType().getId()))
.collect(Collectors.groupingBy(x -> x.getType().getName(), Collectors.counting()));

英文:

How about

return petRepository.findAll().stream()
            .filter(x -&gt; types.getIds().isEmpty() ||
                         types.getIds().contains(x.getType().getId()))
            .collect(Collectors.groupingBy(x -&gt; x.getType().getName(), Collectors.counting()));

huangapple
  • 本文由 发表于 2023年3月9日 15:53:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75681774.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定