- Samman learning hour: 5/5/10/25/5 outline; pairs stop at extracted method taking the lambda as a parameter - exercise/java: pre-factored variant of the kata (Q1/Q4 dead branch stripped, dates as constant), approval test red/flaky by design - exercise/solution: collectExpectedWeather(LongFunction<Boolean>) + no-arg overload; deterministic approval test (all-sunny lambda) - rehearse-with-agent.md: rehearsal setup with qwen + java-refactoring-mcp
1.9 KiB
1.9 KiB
Exercise folder — Split Loop with Lambda (learning hour)
Contents:
java/— pre-factored exercise repo (prefactored-longrange; runs withmvn test)solution/— reference end state after step 3 (extracted method taking the lambda)rehearse-with-agent.md— how Willem rehearses this with qwen-code + java-refactoring-mcp
Reference solution
See solution/. End state of the production code (simplified):
public Map<IceCream, Integer> longRangeForecast() {
return longRangeForecast(daysForward -> {
scorer.updateSelection();
return scorer.lookupWeather(daysForward);
});
}
public Map<IceCream, Integer> longRangeForecast(
LongFunction<Boolean> dayOffsetToWeather) {
var expectedWeather = collectExpectedWeather(dayOffsetToWeather);
// ... reset loop + scoring loop, unchanged ...
}
private static List<Boolean> collectExpectedWeather(
LongFunction<Boolean> dayOffsetToWeather) {
var expectedWeather = new ArrayList<Boolean>();
for (Instant interestingDate : DATES) {
long daysForward = ChronoUnit.DAYS.between(ANCHOR_DATE, interestingDate);
expectedWeather.add(dayOffsetToWeather.apply(daysForward));
}
return expectedWeather;
}
Notes on the end state:
- Key move:
scoreris used only inside the lambda; the extracted methodcollectExpectedWeatherhas no dependency onScorerat all — all its inputs are parameters. - The public no-arg overload keeps callers unchanged; it injects the
"real" weather lambda. The test calls the overload with a pure
daysForward -> trueinstead. - The test is pure and glanceable:
alwaysSunnyweather gives{Strawberry:12, Chocolate:12, Vanilla:17, }(approved file included). scorer.updateSelection()turned out to be deletable (it only mutates staticScorer.flavourstate that this method never reads). Leaving it in the lambda is fine for step 3; deleting it is a debrief aha.