javalambdafunctional-programmingjava-stream

Java Stream processing with if / checking stream state


Given: list of Customers (with Supplier and Agency fields), String agency, String supplier.

Goal: check if any customer supports given agency AND given supplier.

I have a stream that needs to be filtered twice (by two values). If stream is empty after first filtering, I need to check it and throw exception. If it's not empty, I need to process it through second filter (and then check again if it's not empty).

I want to avoid collecting stream to lists if it's possible (and I can't use anyMatch or count methods because they are terminal)

Currently my code look's like:

void checkAgencySupplierMapping(String agency, String supplier) {
   List<Customers> customersFilteredByAgency = allCustomers.stream()
             .filter(customer -> customer.getAgency().equals(agency))
             .collect(toList());

   if (customersFilteredByAgency.isEmpty()) throw new AgencyNotSupportedException(agency);

   customersFilteredByAgency.stream()
             .filter(customer -> customer.getSupplier().equals(supplier))
             .findFirst().orElseThrow(() -> throw new SupplierNotSupportedException(supplier);
}

In this example I skipped some technical details about filtering (eg. parsing Supplier to String).

And I want to achieve something like this:

void checkAgencySupplierMapping(String agency, String supplier) {
    allCustomers.stream()
       .filter(customer -> customer.getAgency().equals(agency))
       .ifEmpty( () -> throw new AgencyNotSupportedException(agency) )
       .filter( customer -> customer.getSupplier().equals(supplier)
       .ifEmpty( () -> throw new SupplierNotSupportedException(supplier); // or findFirst().orElseThrow...
}

Is there any Java 8 feature that will let me checking my Stream status without terminating it?


Solution

  • The code below is a bit ugly but work like you wish.

    First we need to count how many agency of customers match with and then try found the first one supplier match. If there are no matches throw an exception, but here you will check if the cause is that no agency clients were found in order to throw the correct excaption.

    AtomicInteger countAgencyMatches = new AtomicInteger(0);
    
    allCustomers.stream()
            .filter(customer -> {
                if (customer.getAgency().equals(agency)) {
                    countAgencyMatches.incrementAndGet();
                    return true;
                }
    
                return false;
            })
            .filter(customer -> customer.getSupplier().equals(supplier))
            .findFirst()
            .orElseThrow(() -> {
                if (countAgencyMatches.get() == 0) {
                    return new AgencyNotSupportedException(agency);
                }
    
                return new SupplierNotSupportedException(supplier);
            });