Try<V> allows Success(null); Result.Ok rejects null
Context
Try.run() executes a void CheckedRunnable. In Java, Void has no instances, so the successful return value is necessarily null. Result.Ok, on the other hand, models an explicit domain value that must always be meaningful.
Decision
Try.Successacceptsnullas a valid value (produced byTry.run()).Result.Okrejectsnull— its constructor throwsNullPointerException.
Consequences
Positive:
Try.run()can represent void side-effects without requiring a dedicatedUnittype.Resultguarantees that a successful value is always meaningful.
Negative / tradeoffs:
- Deliberate asymmetry between
TryandResultthat must be documented. Try.Success(null).toOption()always returnsNone— surprising behavior if the reason is not known.Try.Success(null).toEither()throwsNullPointerException—Eitherdoes not allow null on either track.
Alternatives considered
- Reject null in both: would require a
Unitor sentinelVoidtype, adding complexity. - Allow null in both: removes the non-null guarantee from
Result, which is part of its safety contract.