Jon Tan
Jon Tan

Reputation: 1551

Logging size of filtered stream

I want this stream to throw an exception if there are more than 1 results that survive the filter. Is there any way to achieve this?

One idea is to use .count(), but I'll have to create the stream again.

Optional<Result> filteredresultSet = results.stream()
        .filter(c -> c.equals("TOMATO))
        .findAny();

Upvotes: 1

Views: 255

Answers (2)

Malte Hartwig
Malte Hartwig

Reputation: 4555

You can replace findAny() by reduce() and throw an exception in the accumulator:

Optional<String> filteredresultSet = results.stream()
                                            .filter("TOMATO"::equals)
                                            .reduce((s1, s2) -> {
                                                throw new MyException();
                                            });

An alternative to find out exactly how many elements are left and still retrieve the first one is to use a small array or custom object to store the count and first element:

results.stream().filter("TOMATO"::equals).collect(Container::new, (c, e) -> {
    c.count++;
    if (c.value == null)
    {
        c.value = e;
    }
}, (c1, c2) -> c1.count += c2.count);

This would return you an instance of Container, or null if the stream is empty. You can then check the count and return an Optional of the value.

Upvotes: 3

Misha
Misha

Reputation: 28163

A simple way is to use .limit(2) on the stream to short-circuit after two matches and then collect to a list or array.

List<Result> filtered = results.stream()
    .filter(c -> c.equals("TOMATO"))
    .limit(2)   // we don't need to know if there are more than 2 matches
    .collect(toList());

if (filtered.size() > 1) {
    // throw or log
}

return filtered.isEmpty() ? Optional.empty() : Optional.of(filtered.get(0));

Upvotes: 1

Related Questions