Skip to content

Add eval for findAny on equivalent matches #51

Description

@martinfrancois

Problem

The Java Streams skill should reinforce using findAny() instead of findFirst() when the matching elements are equivalent or the domain expects at most one match, so encounter order is not part of the result contract.

This is eval-worthy because the correct answer is not a mechanical replacement. The skill must distinguish order-sensitive lookups, such as fallback priority or first line extraction, from equivalent-match lookups where findAny() states the contract better.

Code before the prompt was executed

Several methods used findFirst() for list-name lookups where matching values are equivalent by domain contract. For example:

private static Optional<String> detectedList(List<String> openListNames, String expectedName) {
    return openListNames.stream()
            .filter(name -> name.equalsIgnoreCase(expectedName))
            .findFirst();
}

Another example selected a Trello list by configured normalized name. The configured name is expected to identify one list; if duplicate equivalent names exist, no ordering contract chooses one over the other.

Optional<BoardList> target = context.lists().values().stream()
        .filter(list -> !list.closed())
        .filter(list -> StateNames.normalize(list.name()).equals(StateNames.normalize(inProgressState)))
        .findFirst();

Prompt that caused the implementation

The user asked for a codebase-wide audit of findFirst() and for order-insensitive or single-expected-result lookups to use findAny():

i noticed we have findFirst quite a lot in our code. do a search through the code base, then every single finding you find, check if the order really matters, if so leave it at findFirst and if it doesnt matter or we expect the code to always result in one result anyway and it wouldnt matter if it was multiple which one it is - use findAny

Later prompt that exposed the issue

N/A. This was the direct prompt that caused the refactor.

Prompt-produced code before maintainer correction

N/A. There was no weaker intermediate implementation in this occurrence.

Why the prompt-produced code is bad

The original code is not behaviorally wrong in a sequential stream, but it says the first encounter-order match matters. That is misleading for equivalent exact-name matches or lookups that are expected to have one result.

For these cases, findAny() better communicates that the result is not selected by list position.

Behavior-equivalence analysis

The refactor is safe only for lookups where all matching values are equivalent or the data model expects one match. The audit intentionally kept findFirst() for cases where order is meaningful, including:

  • configured fallback order;
  • PATH lookup order;
  • first line of output or response body;
  • Trello newest-comment ordering;
  • manifest order when tests assert first match wins.

The refactor should not be applied to those cases.

Maintainer-preferred code

private static Optional<String> detectedList(List<String> openListNames, String expectedName) {
    return openListNames.stream()
            .filter(name -> name.equalsIgnoreCase(expectedName))
            .findAny();
}
Optional<BoardList> target = context.lists().values().stream()
        .filter(list -> !list.closed())
        .filter(list -> StateNames.normalize(list.name()).equals(StateNames.normalize(inProgressState)))
        .findAny();

Why the replacement is better

findAny() states that encounter order is not part of the lookup contract. It also makes future reviews easier: a remaining findFirst() should signal a real first-match requirement, not just habit.

Desired eval behavior

  • Reward auditing every findFirst() call before changing code.
  • Reward keeping findFirst() when encounter order, fallback priority, chronological order, PATH order, manifest order, or first-line extraction chooses the result.
  • Reward replacing findFirst() with findAny() when matching values are equivalent or the domain expects at most one match.
  • Reward explaining the semantic reason for each retained findFirst().
  • Reward running focused tests around the changed lookup domains.

Anti-patterns the eval should reject

  • Replacing all findFirst() calls mechanically.
  • Keeping findFirst() only because the stream is currently sequential.
  • Replacing order-sensitive fallback logic with findAny().
  • Replacing first-line or newest-comment logic with findAny().
  • Claiming findAny() is faster without first proving that order is irrelevant.

Suggested eval name

prefer-findany-for-equivalent-matches

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions