Skip to content

Commit b8790c0

Browse files
fix: clarify checked-boundary optional guidance
1 parent 884d4a2 commit b8790c0

2 files changed

Lines changed: 11 additions & 3 deletions

File tree

skills/java-optionals/SKILL.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ Open [references/optional-examples.md](references/optional-examples.md) for work
3131
prompts, or calls a checked parser, do not chase a "zero presence-read" shape at any cost. Prefer
3232
the narrow direct branch and explain it as a checked-boundary exception rather than replacing it
3333
with a generic helper, fake iterable, or `orElse(null)` workaround.
34+
- Before accepting a checked-boundary branch, reduce every non-checked Optional branch first. Keep
35+
only the branch that actually performs checked IO, prompting, or checked parsing. If that leaves a
36+
present-value read after an empty-branch check, make the checked-boundary reason obvious in code
37+
and read the value once.
3438
- A named helper is only acceptable when it names domain work, such as `validateRequestedPort(...)`
3539
or `promptForWorkspace(...)`. Do not add a generic `<T>` helper that accepts `Optional<T>` just to
3640
read the value, make it iterable, or route checked exceptions through Optional.
@@ -92,7 +96,9 @@ Open [references/optional-examples.md](references/optional-examples.md) for work
9296
exception rules, preserve behavior and keep the direct branch instead of inventing another
9397
antipattern. For multiple non-IO Optionals before a checked prompt, select one Optional first
9498
(`or(...)` on Java 9+ or `map(Optional::of).orElseGet(...)` on Java 8), then branch only at the
95-
prompt.
99+
prompt. When a checked-boundary branch must return the present value after the empty branch,
100+
keep that read local, read it once, and add a short comment if otherwise it looks like ordinary
101+
`isEmpty()` followed by `orElseThrow()` value flow.
96102
9. Verify each changed branch. Run the repo's focused Java tests, such as `./mvnw test`,
97103
`mvn test`, `./gradlew test`, or the existing task for the touched code. If no test exists,
98104
trace a small present/absent/fallback case. Confirm the same return values, exceptions, prompts,

skills/java-optionals/references/optional-examples.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,10 @@ final class WorkspaceSelector {
499499
String workspaceId(Options options, Terminal terminal) throws IOException {
500500
Optional<String> configured = options.workspaceId();
501501
if (!configured.isPresent()) {
502+
// Empty branch performs checked IO, so the branch is intentional.
502503
return promptForWorkspace(terminal);
503504
}
504-
return configured.get();
505+
return configured.orElseThrow(() -> new IllegalStateException("workspace id disappeared"));
505506
}
506507

507508
String promptForWorkspace(Terminal terminal) throws IOException {
@@ -527,7 +528,7 @@ Optional<String> selected = options.workspaceId()
527528
.orElseGet(options::environmentWorkspaceId);
528529

529530
if (selected.isPresent()) {
530-
return selected.get();
531+
return selected.orElseThrow(() -> new IllegalStateException("workspace id disappeared"));
531532
}
532533
return promptForWorkspace(terminal);
533534
```
@@ -541,6 +542,7 @@ the Optional into a one-item list or iterable to avoid the branch:
541542
```java
542543
Optional<String> configured = options.workspaceId();
543544
if (configured.isEmpty()) {
545+
// Empty branch performs checked IO, so the branch is intentional.
544546
return promptForWorkspace(terminal);
545547
}
546548
return configured.orElseThrow();

0 commit comments

Comments
 (0)