Java中仅当全部元素匹配条件时收集流且仅处理一次的实现问题
Great question! The core issue here is that you want to avoid calling the external service requestDataForItem at all if even one of the resulting Data objects would be invalid. Let's break down how to handle this based on your specific constraints:
Scenario 1: You can validate items without calling the external service
If you have a way to check whether an Item will produce a valid Data object without invoking requestDataForItem (e.g., using properties of the Item itself), this is the cleanest approach. We'll use allMatch to pre-validate all items first, then only execute the service calls if everything checks out:
// First, verify all items will produce valid Data boolean allItemsWillProduceValidData = items.stream() .allMatch(item -> { // Replace with your pre-validation logic (no external service call!) return item.isEligibleForValidData(); }); List<Data> results = Collections.emptyList(); if (allItemsWillProduceValidData) { // Only call the external service if all items are valid results = items.stream() .map(this::requestDataForItem) .collect(Collectors.toList()); }
This ensures no external service calls are made unless every item is guaranteed to return a valid Data object.
Scenario 2: You must call the service to check validity
If validation requires calling requestDataForItem (since validity is determined by the service response), we can't avoid some service calls—but we can minimize unnecessary ones and ensure we only keep results if all are valid.
Use a loop with short-circuiting to stop calling the service as soon as an invalid Data is found, then discard all results if any invalid entry exists:
List<Data> tempResults = new ArrayList<>(); boolean allValid = true; for (Item item : items) { Data data = requestDataForItem(item); if (!data.isValid()) { allValid = false; // Optional: Add rollback logic here if your service supports it break; // Stop calling the service immediately } tempResults.add(data); } // Only keep results if all are valid; otherwise return empty list List<Data> results = allValid ? tempResults : Collections.emptyList();
Why allMatch alone isn't enough
If you tried using allMatch directly with requestDataForItem, like this:
// This doesn't work for your requirement! boolean allValid = items.stream() .map(this::requestDataForItem) .allMatch(Data::isValid);
It would call the service for items until it hits an invalid one—but those already-made service calls can't be undone, and you won't have collected the valid results if all are valid. This approach fails to meet your "either all calls or none" requirement.
内容的提问来源于stack exchange,提问作者Orest

