Problem
Add a Java Streams skill eval for Collectors.toMap(...) calls where the key or value mapper is an identity lambda such as state -> state, card -> card, or list -> list.
The lesson is small but useful: when a mapper returns its input unchanged, prefer Function.identity() over a hand-written identity lambda. This makes the collector intent clearer and avoids accidental drift where a future edit changes the parameter name or body without noticing that the mapper is meant to be identity.
This is eval-worthy because Codex produced a stream cleanup that correctly used Collectors.toMap(...), but it wrote state -> state instead of the preferred Function.identity(). The Streams skill should have guided that first-pass implementation, not only a later review cleanup.
Code before the prompt was executed
The first method counted normalized states by mutating an external map from a stream terminal operation.
private Map<String, Integer> runningCountsByState() {
Map<String, Integer> counts = new HashMap<>();
running.values().stream()
.map(entry -> StateNames.normalize(entry.card.state()))
.forEach(state -> counts.merge(state, 1, Integer::sum));
return counts;
}
There were also existing toMap(...) call sites that used hand-written identity value mappers.
return normalized.stream()
.collect(Collectors.toMap(Card::id, card -> card, (left, right) -> left, LinkedHashMap::new))
.values()
.stream()
.toList();
Map<String, Card> enriched =
enrichPrerequisites(config, foundCards, true, cardsWithComments(foundCards)).stream()
.collect(Collectors.toMap(Card::id, card -> card, (left, right) -> left, LinkedHashMap::new));
Map<String, BoardList> listMap = fetchBoardLists(config.withResolvedBoardId(boardId)).stream()
.collect(Collectors.toMap(BoardList::id, list -> list, (left, right) -> left, LinkedHashMap::new));
Prompt that caused the implementation
The maintainer asked Codex to continue the existing cleanup plan after installing the Java Streams skill. The active task was to sweep Java sources and apply the Streams skill where it made code meaningfully better.
Relevant instruction:
merged. continue with our plan
Codex then refactored the externally mutated map into a collector-owned result, but did not use Function.identity() for the identity key mapper.
Later prompt that exposed the issue
The maintainer noticed the generated code and asked for a separate cleanup commit:
i noticed you added "collect(Collectors.toMap(state -> state," can you please in a separate commit cleanup all similar cases in the codebase to use Function.identity() and open up an issue in the streams repo with the note that you produced code on your own that didnt use function.identity but thats preferred and the skill should be adjusted to always use function.identity along with evals etc.
The important missed-trigger point is that the Streams skill should have activated during the original collector refactor and preferred Function.identity() immediately.
Prompt-produced code before maintainer correction
This code was produced by Codex during the stream cleanup. It is behaviorally correct, but the identity mapper is unnecessarily hand-written.
private Map<String, Integer> runningCountsByState() {
return running.values().stream()
.map(entry -> StateNames.normalize(entry.card.state()))
.collect(Collectors.toMap(state -> state, state -> 1, Integer::sum, HashMap::new));
}
Why the prompt-produced code is bad
The code is not bad because it is incorrect. It is bad because state -> state is an identity mapper written out manually.
Problems:
state -> state is less explicit than Function.identity() about the mapper's purpose.
- It makes the reader inspect the lambda body to confirm it really returns the input unchanged.
- It is inconsistent with other collector code that should use the same idiom for identity key or value mapping.
- It is easy for a model to repeat this pattern across
toMap(...) calls even when the Java standard library already names the operation.
This should be a generation-time preference in the Streams skill for toMap, groupingBy downstream collectors, and other stream APIs that accept Function<T, T> style identity mappers.
Maintainer-preferred code
Use Function.identity() for identity key and value mappers.
import java.util.function.Function;
private Map<String, Integer> runningCountsByState() {
return running.values().stream()
.map(entry -> StateNames.normalize(entry.card.state()))
.collect(Collectors.toMap(Function.identity(), state -> 1, Integer::sum, HashMap::new));
}
return normalized.stream()
.collect(Collectors.toMap(Card::id, Function.identity(), (left, right) -> left, LinkedHashMap::new))
.values()
.stream()
.toList();
Map<String, Card> enriched =
enrichPrerequisites(config, foundCards, true, cardsWithComments(foundCards)).stream()
.collect(Collectors.toMap(
Card::id, Function.identity(), (left, right) -> left, LinkedHashMap::new));
Map<String, BoardList> listMap = fetchBoardLists(config.withResolvedBoardId(boardId)).stream()
.collect(Collectors.toMap(
BoardList::id, Function.identity(), (left, right) -> left, LinkedHashMap::new));
Why the replacement is better
Function.identity() states the mapper contract directly: the output is the same object/value as the input element.
Benefits:
- The collector reads as an index or count operation rather than an arbitrary lambda transform.
- The identity behavior is named by the Java standard library.
- The result is behavior-preserving: same keys, same values, same merge function, same map supplier.
- It creates a consistent style for
toMap(...) call sites.
Desired eval behavior
- Reward using
Function.identity() for identity key mappers such as state -> state.
- Reward using
Function.identity() for identity value mappers such as card -> card or list -> list.
- Reward keeping explicit merge functions when duplicate keys are possible.
- Reward preserving explicit map suppliers such as
HashMap::new or LinkedHashMap::new when mutability or encounter order matters.
- Reward triggering this preference during the first stream refactor, even when the prompt does not explicitly mention
Function.identity().
Anti-patterns the eval should reject
Collectors.toMap(value -> value, ...) when Function.identity() would express the same key mapper.
Collectors.toMap(..., value -> value, ...) when Function.identity() would express the same value mapper.
- Removing a required duplicate-key merge function while cleaning up identity lambdas.
- Removing a required map supplier while cleaning up identity lambdas.
- Replacing a non-identity mapper with
Function.identity() just because the lambda is short.
- Adding a custom identity helper instead of using
java.util.function.Function.identity().
Suggested eval name
to-map-function-identity-mapper
Problem
Add a Java Streams skill eval for
Collectors.toMap(...)calls where the key or value mapper is an identity lambda such asstate -> state,card -> card, orlist -> list.The lesson is small but useful: when a mapper returns its input unchanged, prefer
Function.identity()over a hand-written identity lambda. This makes the collector intent clearer and avoids accidental drift where a future edit changes the parameter name or body without noticing that the mapper is meant to be identity.This is eval-worthy because Codex produced a stream cleanup that correctly used
Collectors.toMap(...), but it wrotestate -> stateinstead of the preferredFunction.identity(). The Streams skill should have guided that first-pass implementation, not only a later review cleanup.Code before the prompt was executed
The first method counted normalized states by mutating an external map from a stream terminal operation.
There were also existing
toMap(...)call sites that used hand-written identity value mappers.Prompt that caused the implementation
The maintainer asked Codex to continue the existing cleanup plan after installing the Java Streams skill. The active task was to sweep Java sources and apply the Streams skill where it made code meaningfully better.
Relevant instruction:
Codex then refactored the externally mutated map into a collector-owned result, but did not use
Function.identity()for the identity key mapper.Later prompt that exposed the issue
The maintainer noticed the generated code and asked for a separate cleanup commit:
The important missed-trigger point is that the Streams skill should have activated during the original collector refactor and preferred
Function.identity()immediately.Prompt-produced code before maintainer correction
This code was produced by Codex during the stream cleanup. It is behaviorally correct, but the identity mapper is unnecessarily hand-written.
Why the prompt-produced code is bad
The code is not bad because it is incorrect. It is bad because
state -> stateis an identity mapper written out manually.Problems:
state -> stateis less explicit thanFunction.identity()about the mapper's purpose.toMap(...)calls even when the Java standard library already names the operation.This should be a generation-time preference in the Streams skill for
toMap,groupingBydownstream collectors, and other stream APIs that acceptFunction<T, T>style identity mappers.Maintainer-preferred code
Use
Function.identity()for identity key and value mappers.Why the replacement is better
Function.identity()states the mapper contract directly: the output is the same object/value as the input element.Benefits:
toMap(...)call sites.Desired eval behavior
Function.identity()for identity key mappers such asstate -> state.Function.identity()for identity value mappers such ascard -> cardorlist -> list.HashMap::neworLinkedHashMap::newwhen mutability or encounter order matters.Function.identity().Anti-patterns the eval should reject
Collectors.toMap(value -> value, ...)whenFunction.identity()would express the same key mapper.Collectors.toMap(..., value -> value, ...)whenFunction.identity()would express the same value mapper.Function.identity()just because the lambda is short.java.util.function.Function.identity().Suggested eval name
to-map-function-identity-mapper