partitioningBy always returns both keys, so a reconciliation summary can never blow up on an empty side - and a downstream collector shapes each half without a second traversal.
record Txn(String id, String account) {}
var txns = List.of(new Txn("t1", "AC1"), new Txn("t2", "AC9"),
new Txn("t3", "AC2"), new Txn("t4", "AC9"));
var known = Set.of("AC1", "AC2");
Map<Boolean, List<String>> split = txns.stream()
.collect(Collectors.partitioningBy(t -> known.contains(t.account()),
Collectors.mapping(Txn::id, Collectors.toList())));
System.out.println("matched : " + split.get(true));
System.out.println("unmatched: " + split.get(false));
matched : [t1, t3]
unmatched: [t2, t4]
Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.
Published 2026-09-20