A movement report is the union of both key sets with a subtraction on each. getOrDefault(k, 0) is what makes an item that appeared or vanished read as a full gain or loss instead of throwing.
record Snap(String sku, int qty) {}
var monday = List.of(new Snap("S1", 10), new Snap("S2", 5), new Snap("S3", 2));
var friday = List.of(new Snap("S1", 4), new Snap("S2", 5), new Snap("S4", 7));
Map<String, Integer> was = monday.stream().collect(Collectors.toMap(Snap::sku, Snap::qty));
Map<String, Integer> now = friday.stream().collect(Collectors.toMap(Snap::sku, Snap::qty));
var skus = new TreeSet<String>();
skus.addAll(was.keySet());
skus.addAll(now.keySet());
skus.stream()
.map(k -> {
int d = now.getOrDefault(k, 0) - was.getOrDefault(k, 0);
return k + " " + (d > 0 ? "+" : "") + d;
})
.forEach(System.out::println);
S1 -6
S2 0
S3 -2
S4 +7
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