Skip to content

Add eval for findAny on equivalent Optional matches #72

Description

@martinfrancois

Problem

The Java Optionals skill should reliably distinguish findFirst() from findAny() when reviewing or refactoring stream terminal operations that return Optional<T>.

This is eval-worthy because both methods return the same Optional shape, but they communicate different contracts:

  • findFirst() says encounter order is part of the behavior.
  • findAny() says any matching value is equivalent.

The skill should not preserve findFirst() mechanically when the match is expected to be unique or all matches are equivalent, and it should not replace findFirst() when the first matching value is semantically meaningful.

Code before the prompt was executed

The repository had several exact-name or expected-unique lookups using findFirst() even though any equivalent match was acceptable:

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

Another example selected an in-progress list by normalized configured name:

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

There were also order-sensitive findFirst() calls that should stay as findFirst(), such as reading the first version line from command output:

static Optional<Integer> javaMajor(String output) {
    return output.lines()
            .map(String::stripLeading)
            .filter(PrerequisiteChecker::startsWithJavaCommand)
            .map(PrerequisiteChecker::firstInteger)
            .flatMap(Optional::stream)
            .findFirst();
}

Prompt that caused the implementation

The maintainer asked:

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

Then clarified:

also ensure in the cases where you kept findFirst, that there is a test that fails if you change it to findAny. if there isnt, add a test. if you cant create such a test, that means order doesnt matter.

And then refined the rule:

in cases where we have an ordered stream i guess its still better to preserve semantics - so if order does matter still use findFirst even if its not reproducible in a unit test. keep the unit test though

Prompt-produced code before maintainer correction

There was no separate bad implementation in this occurrence. The useful eval is for review/refactor behavior: the skill should guide the agent to audit each findFirst() according to the semantic order contract, not by blindly replacing or preserving all occurrences.

Why a naive Optional review is weak

A weak Optional review treats findFirst() and findAny() as interchangeable because both produce Optional<T>. That misses the semantic difference:

  1. Keeping findFirst() for equivalent exact-name matches overstates an ordering contract that does not matter.
  2. Replacing findFirst() for command output, PATH lookup, fallback lists, or managed comment order can erase a real first-match contract.
  3. A sequential ordered stream may still return the first element from findAny() in tests, so "the test still passes" is not enough proof that order is irrelevant.

Behavior-equivalence analysis

For exact-name configured lookups, every valid match is equivalent or duplicates are outside the meaningful product contract. findAny() is behavior-equivalent and communicates the intent better.

For command output, environment-name priority, PATH lookup, manifest order, setup fallback order, first response line, and Trello managed-comment update order, encounter order is part of the product behavior. findFirst() must stay even when a unit test cannot force the JDK's sequential findAny() implementation to return a later element.

Maintainer-preferred code

Equivalent exact-name lookup:

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

Order-sensitive command output stays as findFirst():

static Optional<Integer> javaMajor(String output) {
    return output.lines()
            .map(String::stripLeading)
            .filter(PrerequisiteChecker::startsWithJavaCommand)
            .map(PrerequisiteChecker::firstInteger)
            .flatMap(Optional::stream)
            .findFirst();
}

Why the replacement is better

Using findAny() for equivalent matches avoids documenting a false first-match dependency. Keeping findFirst() for ordered sources preserves the visible behavior and makes the Optional terminal operation match the domain rule.

The key is not "prefer findAny everywhere". The key is to make the terminal operation match the contract.

Desired eval behavior

  • Reward auditing every findFirst() by asking whether encounter order is part of the required behavior.
  • Reward findAny() when all matches are equivalent or the stream is expected to contain at most one meaningful match.
  • Reward keeping findFirst() when order is the product contract, even if a unit test cannot force a sequential findAny() to fail.
  • Reward adding or keeping first-match scenario tests where later matches would be wrong.
  • Reward explaining the difference between semantic order and mechanically reproducible mutation failure.

Anti-patterns the eval should reject

  • Blindly replacing every findFirst() with findAny().
  • Blindly preserving every findFirst() because it already works.
  • Claiming order does not matter only because tests still pass after using findAny().
  • Using findFirst() for exact-name duplicate matches where duplicates are equivalent and no first-match behavior is promised.
  • Removing first-match behavior from PATH lookup, fallback priority, command output, first-line rendering, or ordered comment update code.

Suggested eval name

find-any-for-equivalent-matches-but-preserve-ordered-first-match-contracts

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