Interface Guard<T>

Type Parameters:
T - the type of value being validated
Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

@FunctionalInterface @NullMarked public interface Guard<T>
A named, composable predicate that produces a Validated result when applied to a value.

Guard<T> is a @FunctionalInterface whose single abstract method is check(T), which returns Validated<NonEmptyList<String>, T>: Valid(value) when the predicate passes, or Invalid(errors) when it fails. All composition operators (and(Guard), or(Guard), negate(), andThen(Guard), contramap(Function), withMessage(String)) are default methods, so guards can be defined as lambdas and composed without inheritance; allOf(Guard, Guard...) and anyOf(Guard, Guard...) compose several guards at once. The choice to use @FunctionalInterface with default methods rather than an abstract class is documented in ADR-011 — Guard<T> as a @FunctionalInterface with default methods.

Guards are designed to be defined once and reused across validation pipelines, eliminating the repetitive if/Validated.invalidNel(Object) pattern:

Guard<String> notBlank     = Guard.of(s -> !s.isBlank(),         "must not be blank");
Guard<String> minLength3   = Guard.of(s -> s.length() >= 3,      "must be at least 3 chars");
Guard<String> alphanumeric = Guard.of(s -> s.matches("[\\w]+"),  "must be alphanumeric");

Guard<String> username = notBlank.and(minLength3).and(alphanumeric);

username.check("al");  // Invalid(["must be at least 3 chars"])
username.check("ok?"); // Invalid(["must be alphanumeric"])
username.check("alice"); // Valid("alice")

Error type

The error type is fixed as NonEmptyList<String> — human-readable messages accumulated across all failing guards. This design avoids requiring a BinaryOperator<E> for merging in and(Guard)/or(Guard), and guarantees at least one error is always present. The trade-off is that typed domain error objects require working directly with Validated<E, A> instead. This decision is documented in ADR-005 — Guard<T> accumulates errors as a fixed NonEmptyList<String>.

Composition semantics

  • and — both guards must pass; errors from all failing guards are accumulated (not fail-fast).
  • or — the first passing guard short-circuits; if all fail, all errors are accumulated.
  • negate / negate(message) / negate(messageFromValue) — inverts the predicate.
  • Method Summary

    Modifier and Type
    Method
    Description
    static <T> Guard<T>
    allOf(Guard<? super T> first, Guard<? super T>... rest)
    Returns a guard that passes only when all of the given guards pass.
    default Guard<T>
    and(Guard<? super T> other)
    Returns a composed guard that requires both this guard and other to pass.
    default Guard<T>
    andThen(Guard<? super T> next)
    Returns a composed guard that evaluates next only when this guard passes.
    static <T> Guard<T>
    anyOf(Guard<? super T> first, Guard<? super T>... rest)
    Returns a guard that passes when at least one of the given guards passes.
    default Predicate<T>
    Returns a standard Predicate<T> that returns true when this guard passes and false when it fails.
    check(T value)
    Applies this guard to value.
    Applies this guard to value and returns an Either<NonEmptyList<String>, T>.
    default Option<T>
    Applies this guard to value and returns an Option<T>.
    default Optional<T>
    Applies this guard to value and returns a standard Optional<T>.
    Applies this guard to value and returns a Result<T, NonEmptyList<String>>.
    default <E> Result<T,E>
    checkToResult(T value, Function<? super NonEmptyList<String>, ? extends E> toError)
    Applies this guard to value and returns a Result<T, E>, mapping the accumulated error list to a domain-specific error type via toError.
    default Try<T>
    checkToTry(T value)
    Applies this guard to value and returns a Try<T>.
    default <X extends Throwable>
    Try<T>
    checkToTry(T value, Function<? super NonEmptyList<String>, ? extends X> toThrowable)
    Applies this guard to value and returns a Try<T>, converting any accumulated errors to a domain-specific Throwable via toThrowable.
    default <U> Guard<U>
    contramap(Function<? super U, ? extends T> mapper)
    Returns a Guard<U> that applies mapper to its input before checking.
    default <U> Guard<U>
    contramap(Function<? super U, ? extends T> mapper, String fieldName)
    Returns a Guard<U> that applies mapper to its input before checking, prefixing every error message with fieldName.
    default Guard<T>
    mapMessages(Function<? super String, String> transform)
    Returns a guard that rewrites every error message produced by this guard with transform, leaving valid results untouched.
    static <T> Guard<T>
    narrow(Guard<? super T> guard)
    Adapts a Guard<? super T> to a Guard<T> by re-wrapping the checked value, preserving the accumulated errors on failure.
    default Guard<T>
    Returns a guard that is the logical negation of this guard, using a generic error message.
    default Guard<T>
    negate(String errorMessage)
    Returns a guard that is the logical negation of this guard, using the supplied error message when the original guard passes.
    default Guard<T>
    negate(Function<? super T, String> messageFromValue)
    Returns a guard that is the logical negation of this guard, using a dynamic error message.
    static <T extends @Nullable Object>
    Guard<T>
    Creates and returns a Guard instance that ensures a value is non-null.
    static <T> Guard<T>
    of(Predicate<? super T> predicate, String errorMessage)
    Creates a Guard<T> from a predicate and a static error message.
    static <T> Guard<T>
    of(Predicate<? super T> predicate, Function<? super T, String> errorMessageFn)
    Creates a Guard<T> from a predicate and a dynamic error message function.
    static <T> Guard<T>
    ofCatching(Predicate<? super T> predicate, String errorMessage)
    Creates a Guard<T> from a predicate that may throw, treating a thrown RuntimeException as a failed check.
    default Guard<T>
    or(Guard<? super T> other)
    Returns a composed guard that passes when at least one of this guard or other passes.
    default Guard<T>
    Returns a guard that replaces any error messages produced by this guard with message.
  • Method Details

    • check

      Validated<NonEmptyList<String>, T> check(T value)
      Applies this guard to value.

      Contract: a guard is a validator, not a transformer — an implementation must return Valid of the checked value itself, never a substituted or normalized one. The composition operators rely on this: they re-wrap the original input, so any value produced by a contract-violating guard is discarded during composition. Note also that Valid rejects null, so a guard over a nullable type can never pass a null value — it must reject it (see nonNull()).

      Parameters:
      value - the value to validate
      Returns:
      Valid(value) if the predicate passes, or Invalid(errors) if it fails
    • of

      static <T> Guard<T> of(Predicate<? super T> predicate, String errorMessage)
      Creates a Guard<T> from a predicate and a static error message.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      

      The predicate must not throw: any exception it raises escapes check(Object) unwrapped, breaking the contract that a guard always returns a Validated. For predicates that would throw on null input, compose with nonNull().andThen(...) so the null check short-circuits first; for predicates that may throw on other inputs (parsing, regex on malformed data), use ofCatching(Predicate, String).

      Type Parameters:
      T - the value type
      Parameters:
      predicate - the condition that must hold for the value to be valid; must not throw
      errorMessage - the error message produced when the predicate fails
      Returns:
      a new Guard<T>
      Throws:
      NullPointerException - if predicate or errorMessage is null
    • of

      static <T> Guard<T> of(Predicate<? super T> predicate, Function<? super T, String> errorMessageFn)
      Creates a Guard<T> from a predicate and a dynamic error message function.

      The errorMessageFn receives the failing value so it can produce a context-specific message.

      Example:

      Guard<Integer> max = Guard.of(
          n -> n <= 100,
          n -> "must be ≤ 100, got " + n
      );
      

      The predicate must not throw: any exception it raises escapes check(Object) unwrapped, breaking the contract that a guard always returns a Validated. For predicates that would throw on null input, compose with nonNull().andThen(...) so the null check short-circuits first; for predicates that may throw on other inputs (parsing, regex on malformed data), use ofCatching(Predicate, String).

      Type Parameters:
      T - the value type
      Parameters:
      predicate - the condition that must hold for the value to be valid; must not throw
      errorMessageFn - function that produces an error message from the failing value
      Returns:
      a new Guard<T>
      Throws:
      NullPointerException - if predicate or errorMessageFn is null
    • ofCatching

      static <T> Guard<T> ofCatching(Predicate<? super T> predicate, String errorMessage)
      Creates a Guard<T> from a predicate that may throw, treating a thrown RuntimeException as a failed check.

      Unlike of(Predicate, String), whose predicate must not throw, this factory preserves the contract that a guard always returns a Validated: if the predicate throws a RuntimeException, the guard returns Invalid([errorMessage]) exactly as if the predicate had returned false. Errors and other Throwables still propagate.

      Example:

      Guard<String> numeric = Guard.ofCatching(
          s -> Integer.parseInt(s) >= 0,       // parseInt throws on non-numeric input
          "must be a non-negative number");
      
      numeric.check("42");   // Valid("42")
      numeric.check("abc");  // Invalid(["must be a non-negative number"]) — exception folded
      
      Type Parameters:
      T - the value type
      Parameters:
      predicate - the condition to evaluate; a thrown RuntimeException counts as a failure
      errorMessage - the error message produced when the predicate fails or throws
      Returns:
      a new Guard<T>
      Throws:
      NullPointerException - if predicate or errorMessage is null
    • nonNull

      static <T extends @Nullable Object> Guard<T> nonNull()
      Creates and returns a Guard instance that ensures a value is non-null.
      Type Parameters:
      T - the type of the value to be guarded
      Returns:
      a Guard that validates the value is not null
    • allOf

      @SafeVarargs static <T> Guard<T> allOf(Guard<? super T> first, Guard<? super T>... rest)
      Returns a guard that passes only when all of the given guards pass.

      Same semantics as chaining and: every guard is always evaluated and errors from all failing guards are accumulated in order — not fail-fast. The first parameter is mandatory, so the composition is never empty. Unlike a manual and chain, the guards are evaluated in a single pass with one error list.

      Example:

      Guard<String> username = Guard.allOf(notBlank, minLength3, alphanumeric);
      
      username.check("a?");   // Invalid(["must be at least 3 chars", "must be alphanumeric"])
      username.check("alice"); // Valid("alice")
      
      Type Parameters:
      T - the value type
      Parameters:
      first - the first guard; must not be null
      rest - the remaining guards; must not be null or contain null
      Returns:
      a composed Guard<T> requiring every guard to pass
      Throws:
      NullPointerException - if first, rest, or any element is null
    • anyOf

      @SafeVarargs static <T> Guard<T> anyOf(Guard<? super T> first, Guard<? super T>... rest)
      Returns a guard that passes when at least one of the given guards passes.

      Same semantics as chaining or: evaluation short-circuits on the first passing guard; if every guard fails, errors from all of them are accumulated in order. The first parameter is mandatory, so the composition is never empty.

      Example:

      Guard<String> contact = Guard.anyOf(email, phone);
      
      contact.check("alice@example.com"); // Valid — phone never evaluated
      contact.check("hello");             // Invalid(["must contain @", "must be digits"])
      
      Type Parameters:
      T - the value type
      Parameters:
      first - the first guard; must not be null
      rest - the remaining guards; must not be null or contain null
      Returns:
      a composed Guard<T> requiring at least one guard to pass
      Throws:
      NullPointerException - if first, rest, or any element is null
    • narrow

      static <T> Guard<T> narrow(Guard<? super T> guard)
      Adapts a Guard<? super T> to a Guard<T> by re-wrapping the checked value, preserving the accumulated errors on failure.

      Use this when assigning or passing a guard written against a supertype where a Guard<T> is required outside the variance-aware combinators — the adaptation cannot be written as a plain lambda because the Validated value types differ:

      Guard<CharSequence> notEmpty = Guard.of(cs -> !cs.isEmpty(), "must not be empty");
      Guard<String> forStrings = Guard.narrow(notEmpty);
      
      Type Parameters:
      T - the narrower value type
      Parameters:
      guard - the guard written against a supertype; must not be null
      Returns:
      a Guard<T> delegating to guard
      Throws:
      NullPointerException - if guard is null
    • and

      default Guard<T> and(Guard<? super T> other)
      Returns a composed guard that requires both this guard and other to pass.

      Both guards are always evaluated — this is not fail-fast. Errors from all failing guards are accumulated into a single NonEmptyList, so the caller receives a complete picture of all violations at once.

      Example:

      Guard<Integer> positive = Guard.of(n -> n > 0,      "must be positive");
      Guard<Integer> even     = Guard.of(n -> n % 2 == 0, "must be even");
      Guard<Integer> positiveEven = positive.and(even);
      
      positiveEven.check(4);   // Valid(4)
      positiveEven.check(3);   // Invalid(["must be even"])
      positiveEven.check(-1);  // Invalid(["must be positive", "must be even"])
                               //  — both guards evaluated, both errors collected
      

      The parameter is contravariant (Guard<? super T>), mirroring Predicate.and, so a guard written against a supertype (e.g. Guard<CharSequence>) can be composed into a Guard<String>.

      Parameters:
      other - the guard that must also pass; must not be null
      Returns:
      a composed Guard<T>
      Throws:
      NullPointerException - if other is null
    • andThen

      default Guard<T> andThen(Guard<? super T> next)
      Returns a composed guard that evaluates next only when this guard passes.

      Unlike and, evaluation is short-circuit: if this guard returns Invalid, next is never called and its error is never accumulated. This makes andThen the safe choice when the downstream guard's predicate would throw on the values rejected by this guard — most notably when composing nonNull() with a rule that dereferences the value:

      Guard<@Nullable String> nonNullAndNotBlank =
          Guard.<@Nullable String>nonNull()
              .andThen(Guard.<@Nullable String>of(s -> s != null && !s.isBlank(),
                                                  "must not be blank"));
      
      nonNullAndNotBlank.check("hello"); // Valid("hello")
      nonNullAndNotBlank.check(null);    // Invalid(["must not be null"]) — next not evaluated
      nonNullAndNotBlank.check("   ");   // Invalid(["must not be blank"])
      

      Use and when you want both guards evaluated regardless of the first result (error accumulation). Use andThen when the second guard must not run until the first has passed.

      The parameter is contravariant (Guard<? super T>); the composed guard re-wraps the original value, so the result type stays Guard<T>.

      Parameters:
      next - the guard to evaluate when this guard passes; must not be null
      Returns:
      a composed Guard<T>
      Throws:
      NullPointerException - if next is null
    • or

      default Guard<T> or(Guard<? super T> other)
      Returns a composed guard that passes when at least one of this guard or other passes.

      Evaluation is short-circuit: if this guard passes, other is never evaluated. If both fail, errors from both guards are accumulated.

      Example:

      Guard<String> email = Guard.of(s -> s.contains("@"),  "must contain @");
      Guard<String> phone = Guard.of(s -> s.matches("\\d+"), "must be digits");
      Guard<String> contact = email.or(phone);
      
      contact.check("alice@example.com");  // Valid — email passes, phone not evaluated
      contact.check("12345");             // Valid — phone passes
      contact.check("hello");             // Invalid(["must contain @", "must be digits"])
      

      The parameter is contravariant (Guard<? super T>), mirroring Predicate.or; the composed guard re-wraps the original value, so the result type stays Guard<T>.

      Parameters:
      other - the alternative guard; must not be null
      Returns:
      a composed Guard<T>
      Throws:
      NullPointerException - if other is null
    • negate

      default Guard<T> negate()
      Returns a guard that is the logical negation of this guard, using a generic error message.

      The composed guard returns Valid(value) when this guard fails, and Invalid(["must not satisfy the condition"]) when this guard passes. Use negate(message) to supply a domain-specific error message.

      Returns:
      the negated Guard<T>
    • negate

      default Guard<T> negate(String errorMessage)
      Returns a guard that is the logical negation of this guard, using the supplied error message when the original guard passes.

      Example:

      Guard<String> notAdmin = Guard.of(s -> s.equals("admin"), "is admin")
                                    .negate("username must not be 'admin'");
      
      notAdmin.check("alice"); // Valid("alice")
      notAdmin.check("admin"); // Invalid(["username must not be 'admin'"])
      
      Parameters:
      errorMessage - the error message returned when the original guard passes
      Returns:
      the negated Guard<T>
      Throws:
      NullPointerException - if errorMessage is null
    • negate

      default Guard<T> negate(Function<? super T, String> messageFromValue)
      Returns a guard that is the logical negation of this guard, using a dynamic error message.

      The messageFromValue function receives the value that passed the original guard, allowing a context-specific error message.

      Example:

      Guard<String> notReserved = Guard.of(s -> s.equals("admin") || s.equals("root"), "")
          .negate(s -> "username '" + s + "' is reserved");
      
      notReserved.check("alice"); // Valid("alice")
      notReserved.check("admin"); // Invalid(["username 'admin' is reserved"])
      
      Parameters:
      messageFromValue - function producing an error message from the passing value; must not be null
      Returns:
      the negated Guard<T>
      Throws:
      NullPointerException - if messageFromValue is null
    • withMessage

      default Guard<T> withMessage(String message)
      Returns a guard that replaces any error messages produced by this guard with message.

      Useful when you want to expose a single clean message at a public API boundary regardless of the internal validation details.

      Example:

      Guard<String> username = notBlank.and(minLength3).withMessage("invalid username");
      
      username.check("");    // Invalid(["invalid username"])
      username.check("a");   // Invalid(["invalid username"])
      username.check("alice"); // Valid("alice")
      
      Parameters:
      message - the replacement error message; must not be null
      Returns:
      a new Guard<T> that returns a single fixed error when this guard fails
      Throws:
      NullPointerException - if message is null
    • asPredicate

      default Predicate<T> asPredicate()
      Returns a standard Predicate<T> that returns true when this guard passes and false when it fails.

      Use this to integrate guards with standard Java APIs that accept Predicate (e.g., Stream.filter, Collection.removeIf).

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      
      List<String> valid = Stream.of("alice", "  ", "bob", "")
          .filter(notBlank.asPredicate())
          .toList();
      // ["alice", "bob"]
      
      Returns:
      a Predicate<T> backed by this guard
    • contramap

      default <U> Guard<U> contramap(Function<? super U, ? extends T> mapper)
      Returns a Guard<U> that applies mapper to its input before checking.

      This is the contravariant map operation: it adapts a guard written for type T to work on an enclosing type U by projecting U → T first. It is the idiomatic way to reuse field-level guards on whole objects.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "username must not be blank");
      
      // Lift notBlank to validate User objects by their username field
      Guard<User> userGuard = notBlank.contramap(User::username);
      
      userGuard.check(new User("alice")); // Valid(user)
      userGuard.check(new User("   "));   // Invalid(["username must not be blank"])
      
      Type Parameters:
      U - the input type of the returned guard
      Parameters:
      mapper - function that extracts the T value from a U; must not be null
      Returns:
      a new Guard<U> that projects U → T before checking
      Throws:
      NullPointerException - if mapper is null
    • contramap

      default <U> Guard<U> contramap(Function<? super U, ? extends T> mapper, String fieldName)
      Returns a Guard<U> that applies mapper to its input before checking, prefixing every error message with fieldName.

      Like contramap(Function), but each accumulated error is rewritten as "fieldName: originalMessage", so messages stay unambiguous when several field-level guards are combined on the same object.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      
      Guard<User> userGuard = Guard.allOf(
          notBlank.contramap(User::username, "username"),
          notBlank.contramap(User::email,    "email"));
      
      userGuard.check(new User(" ", " "));
      // Invalid(["username: must not be blank", "email: must not be blank"])
      
      Type Parameters:
      U - the input type of the returned guard
      Parameters:
      mapper - function that extracts the T value from a U; must not be null
      fieldName - prefix identifying the projected field in error messages; must not be null
      Returns:
      a new Guard<U> that projects U → T before checking and prefixes errors with fieldName
      Throws:
      NullPointerException - if mapper or fieldName is null
    • mapMessages

      default Guard<T> mapMessages(Function<? super String, String> transform)
      Returns a guard that rewrites every error message produced by this guard with transform, leaving valid results untouched.

      This is the general form behind contramap(Function, String)'s field prefixing — use it directly for any other message convention: nested paths, i18n keys, suffixes, or structured formats.

      Example:

      Guard<String> username = notBlank.and(minLength3)
          .mapMessages(m -> "user.name: " + m);
      
      username.check("");  // Invalid(["user.name: must not be blank", ...])
      

      Unlike withMessage(String), which collapses all errors into one fixed message, mapMessages transforms each accumulated message individually.

      Parameters:
      transform - function applied to each error message; must not be null and must not return null
      Returns:
      a new Guard<T> with rewritten error messages
      Throws:
      NullPointerException - if transform is null
    • checkToResult

      default Result<T, NonEmptyList<String>> checkToResult(T value)
      Applies this guard to value and returns a Result<T, NonEmptyList<String>>.

      Equivalent to this.check(value).toResult() but removes the need to import and chain the conversion manually.

      Parameters:
      value - the value to validate
      Returns:
      Result.ok(value) if the guard passes, or Result.err(errors) if it fails
    • checkToResult

      default <E> Result<T,E> checkToResult(T value, Function<? super NonEmptyList<String>, ? extends E> toError)
      Applies this guard to value and returns a Result<T, E>, mapping the accumulated error list to a domain-specific error type via toError.

      Use this at domain service boundaries where Result is the preferred container and the error type is richer than a plain list of strings.

      Example:

      Guard<String> username = notBlank.and(minLength3);
      
      Result<String, ValidationException> result = username.checkToResult(
          input,
          errors -> new ValidationException("username", errors.toList())
      );
      
      Type Parameters:
      E - the domain error type
      Parameters:
      value - the value to validate
      toError - function mapping the accumulated error list to E
      Returns:
      Result.ok(value) on success, or Result.err(toError(errors)) on failure
      Throws:
      NullPointerException - if toError is null
    • checkToOption

      default Option<T> checkToOption(T value)
      Applies this guard to value and returns an Option<T>.

      Returns Some(value) when the guard passes and None when it fails, discarding the error details. Use this when you only need to know whether a value is valid, not why it is not.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      
      // Filter a stream keeping only valid values
      List<String> valid = Stream.of("alice", "  ", "bob")
          .flatMap(s -> notBlank.checkToOption(s).stream())
          .toList();
      // ["alice", "bob"]
      

      A guard can never produce Valid(null)Validated.Valid rejects null at construction — so the returned Option never wraps null; a guard over a nullable type must reject null (see check(Object)).

      Parameters:
      value - the value to validate
      Returns:
      Option.some(value) if the guard passes, or Option.none() if it fails
    • checkToEither

      default Either<NonEmptyList<String>, T> checkToEither(T value)
      Applies this guard to value and returns an Either<NonEmptyList<String>, T>.

      Returns Either.right(value) when the guard passes and Either.left(errors) when it fails. Use this when downstream logic is already expressed in terms of Either.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      
      Either<NonEmptyList<String>, String> right = notBlank.checkToEither("hello");
      // Either.right("hello")
      
      Either<NonEmptyList<String>, String> left = notBlank.checkToEither("   ");
      // Either.left(NonEmptyList.of("must not be blank"))
      
      Parameters:
      value - the value to validate
      Returns:
      Either.right(value) if the guard passes, or Either.left(errors) if it fails
    • checkToTry

      default Try<T> checkToTry(T value)
      Applies this guard to value and returns a Try<T>.

      Returns Try.success(value) when the guard passes. When it fails, the accumulated error messages are joined with "; " and wrapped in an IllegalArgumentException. Use checkToTry(Object, Function) to supply a domain-specific exception instead.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      
      Try<String> success = notBlank.checkToTry("hello");
      // Try.success("hello")
      
      Try<String> failure = notBlank.checkToTry("   ");
      // Try.failure(new IllegalArgumentException("must not be blank"))
      
      Parameters:
      value - the value to validate
      Returns:
      Try.success(value) if the guard passes, or a Try.failure wrapping an IllegalArgumentException with the joined error messages
    • checkToTry

      default <X extends Throwable> Try<T> checkToTry(T value, Function<? super NonEmptyList<String>, ? extends X> toThrowable)
      Applies this guard to value and returns a Try<T>, converting any accumulated errors to a domain-specific Throwable via toThrowable.

      Use this at boundaries where the caller controls the exception type.

      Example:

      Guard<String> username = notBlank.and(minLength3);
      
      Try<String> result = username.checkToTry(
          input,
          errors -> new ValidationException(errors.toList())
      );
      
      Type Parameters:
      X - the throwable type
      Parameters:
      value - the value to validate
      toThrowable - function mapping the accumulated error list to a Throwable; must not be null
      Returns:
      Try.success(value) if the guard passes, or Try.failure(toThrowable(errors)) if it fails
      Throws:
      NullPointerException - if toThrowable is null
    • checkToOptional

      default Optional<T> checkToOptional(T value)
      Applies this guard to value and returns a standard Optional<T>.

      Returns Optional.of(value) when the guard passes and Optional.empty() when it fails, discarding the error details. Use this to integrate with Java standard library APIs that work with Optional.

      Example:

      Guard<String> notBlank = Guard.of(s -> !s.isBlank(), "must not be blank");
      
      Optional<String> present = notBlank.checkToOptional("hello"); // Optional.of("hello")
      Optional<String> empty   = notBlank.checkToOptional("   ");   // Optional.empty()
      

      A guard can never produce Valid(null)Validated.Valid rejects null at construction — so this method never passes null to Optional.of(Object); a guard over a nullable type must reject null (see check(Object)). Note that Optional.of(value) wraps the input: for a Guard<@Nullable T> checking a null input, the guard must return Invalid, which yields Optional.empty() here.

      Parameters:
      value - the value to validate
      Returns:
      Optional.of(value) if the guard passes, Optional.empty() if the guard fails