A class for functional error handling in Java 8, either a success with a value or a failure with error(s)
Available from the Central Repository. In Maven style:
<dependency>
<groupId>co.unruly</groupId>
<artifactId>validation</artifactId>
<version>1.0</version>
</dependency>
Validation<String,String> success = Validation.success("woot");
Validation<String,String> failure = Validation.failure("awww");
The first type parameter T is the type of a successful value, the latter S the type of error(s)
boolean success = validation.isSuccess();
boolean failure = validation.isFailure();
T value = validation.get();
List<S> errors = validation.getErrors()
// Add one to contents
Validation.success(2).map(i -> i + 1);
// Add one to contents using flatMap
Validation.success(2).flatMap(i -> Validation.success(i + 1));
Map and flatMap operate on the value of a successful Validation. They do not affect a failure Validation.
Validation.success(2).filter(i -> i > 1);
Filtering a success with a non-truthy predicate will turn it into a failure with empty errors. It does not affect a failure.
Validation.tryTo(() -> /* do something that may throw */)
If an exception is thrown, tryTo will return a failure validation with the exception in the errors.
validation.tryMap(...)
validation.tryFlatMap(...)
validation.tryFilter(...)
If an exception is thrown, the Validation is a failure with the exception in the errors.
There are a couple of caveats here:
- The type of the errors of the returned Validation is Object
- If function f throws and function g catches then
map(f).map(g)
may not equal.map(g compose f)
Validation.success(3).compose(Validation.success(4), (a, b) -> a * b);
Two composed successes produce a success with the values combined using the provided function. Otherwise a failure is produced, including errors from each.
There are also some static methods for composing many Validations of type T for a few common types T (Integer, Long, Float, Double, Boolean, Collection, Map) with a sensible default composition function:
Validation.compose(() -> Validation.success(3L), () -> Validation.success(4L));
The use of lambda suppliers here is a pattern for working around Java's type erasure.
From Scala:
From Scalaz:
From Rust:
There are many similar types in other functional languages.