Problem
The Streams skill should catch a case where a stream already computes exactly the data a method returns, but the implementation first materializes a temporary list and then mutates a separate set with addAll(...).
This is eval-worthy because replacing stream().forEach(set::add) with toList() plus set.addAll(...) can still leave unnecessary intermediate state. The skill should prefer making the stream own the final collection result when mutability is not needed.
Code before the prompt was executed
The method scanned local workflow files, extracted optional server ports, collected them into a temporary list, and then copied that list into a mutable HashSet before returning it.
private Set<Integer> localWorkflowFilePortReservations(Options options, ConnectedBoard ignoredBoard) {
Set<Integer> reserved = new HashSet<>();
Path configDir = options.configDir();
if (configDir == null || !Files.isDirectory(configDir)) {
return reserved;
}
try (var files = Files.list(configDir)) {
List<Integer> workflowPorts = files.filter(Files::isRegularFile)
.filter(file -> PathNames.fileName(file).endsWith(".md"))
.filter(file -> ignoredBoard.workflowPath() == null
|| !PathsEqual.samePath(file, ignoredBoard.workflowPath()))
.map(file -> workflowConfig.serverPort(
file, WorkflowEnvironmentResolver.resolver(environment, options.envPath())))
.flatMap(Optional::stream)
.toList();
reserved.addAll(workflowPorts);
} catch (IOException ignored) {
// A config directory that cannot be listed leaves only the manifest and probe checks.
}
return reserved;
}
Prompt that caused the implementation
The earlier cleanup prompt asked for repeated Java Streams and Optional cleanup passes across the codebase, including replacing stream mutation patterns and checking for remaining stream antipatterns. The implementation focused on removing direct forEach(...) mutation, but still left this temporary-list-then-addAll(...) shape.
Later prompt that exposed the issue
A review comment asked:
Is there really no better way here? Use the streams skill
The comment pointed at reserved.addAll(workflowPorts); after workflowPorts had just been produced by a stream.
Prompt-produced code before maintainer correction
Same as the code before the prompt: the stream produced workflowPorts, then reserved.addAll(workflowPorts) copied it into the returned set.
Why the prompt-produced code is weak
The code is functionally correct, but the temporary list is unnecessary:
- The method returns the collected ports directly.
- The returned collection does not need to be mutable.
- The list allocation does not express the result type; it is only an intermediate copy source.
- Replacing external mutation with
toList() is incomplete when the next line immediately mutates another collection with the list.
Behavior-equivalence analysis
The final code preserves behavior:
- Missing or non-directory config dirs still return an empty set.
- Unreadable config dirs still return an empty set.
- Duplicate ports are still collapsed because the method returns a set.
- The caller only merges the returned ports into another set, so the returned collection does not need to be mutable.
- Encounter order is not part of the contract because the result is used for membership checks.
Maintainer-preferred code
private Set<Integer> localWorkflowFilePortReservations(Options options, ConnectedBoard ignoredBoard) {
Path configDir = options.configDir();
if (configDir == null || !Files.isDirectory(configDir)) {
return Set.of();
}
try (var files = Files.list(configDir)) {
return files.filter(Files::isRegularFile)
.filter(file -> PathNames.fileName(file).endsWith(".md"))
.filter(file -> ignoredBoard.workflowPath() == null
|| !PathsEqual.samePath(file, ignoredBoard.workflowPath()))
.map(file -> workflowConfig.serverPort(
file, WorkflowEnvironmentResolver.resolver(environment, options.envPath())))
.flatMap(Optional::stream)
.collect(toImmutableSet());
} catch (IOException ignored) {
// A config directory that cannot be listed leaves only the manifest and probe checks.
return Set.of();
}
}
Why the replacement is better
The stream now owns the final result. There is no temporary list and no extra mutable set inside the helper. toImmutableSet() makes it explicit that callers should not mutate the helper result, while still preserving the membership semantics the caller needs.
Desired eval behavior
- Reward detecting stream output that is immediately copied into another collection with
addAll(...).
- Reward checking whether the returned collection must be mutable before choosing the collector.
- Reward producing the final collection directly from the stream when behavior is preserved.
- Reward explaining that
toList() plus addAll(...) may still be weaker than collecting directly to the needed result type.
- Reward preserving exception and empty-directory behavior around
Files.list(...).
Anti-patterns the eval should reject
- Replacing
addAll(...) with stream().forEach(set::add).
- Keeping
toList() only to immediately copy it into a returned collection.
- Using
Collectors.toSet() in a codebase where the result mutability is intentionally avoided or where lint forbids ambiguous JDK collectors.
- Changing IO exception handling or probing behavior while doing the stream cleanup.
Suggested eval name
collect-final-set-instead-of-list-addall
Problem
The Streams skill should catch a case where a stream already computes exactly the data a method returns, but the implementation first materializes a temporary list and then mutates a separate set with
addAll(...).This is eval-worthy because replacing
stream().forEach(set::add)withtoList()plusset.addAll(...)can still leave unnecessary intermediate state. The skill should prefer making the stream own the final collection result when mutability is not needed.Code before the prompt was executed
The method scanned local workflow files, extracted optional server ports, collected them into a temporary list, and then copied that list into a mutable
HashSetbefore returning it.Prompt that caused the implementation
The earlier cleanup prompt asked for repeated Java Streams and Optional cleanup passes across the codebase, including replacing stream mutation patterns and checking for remaining stream antipatterns. The implementation focused on removing direct
forEach(...)mutation, but still left this temporary-list-then-addAll(...)shape.Later prompt that exposed the issue
A review comment asked:
The comment pointed at
reserved.addAll(workflowPorts);afterworkflowPortshad just been produced by a stream.Prompt-produced code before maintainer correction
Same as the code before the prompt: the stream produced
workflowPorts, thenreserved.addAll(workflowPorts)copied it into the returned set.Why the prompt-produced code is weak
The code is functionally correct, but the temporary list is unnecessary:
toList()is incomplete when the next line immediately mutates another collection with the list.Behavior-equivalence analysis
The final code preserves behavior:
Maintainer-preferred code
Why the replacement is better
The stream now owns the final result. There is no temporary list and no extra mutable set inside the helper.
toImmutableSet()makes it explicit that callers should not mutate the helper result, while still preserving the membership semantics the caller needs.Desired eval behavior
addAll(...).toList()plusaddAll(...)may still be weaker than collecting directly to the needed result type.Files.list(...).Anti-patterns the eval should reject
addAll(...)withstream().forEach(set::add).toList()only to immediately copy it into a returned collection.Collectors.toSet()in a codebase where the result mutability is intentionally avoided or where lint forbids ambiguous JDK collectors.Suggested eval name
collect-final-set-instead-of-list-addall