The Either
type is closely related to Optional
, but can have different "failure" states, other than only empty.
Either
can be used to collect error messages in stream operations,
or simply as a lightweight alternative to throwing an Exception.
There are several popular libraries that offer an Either
type,
including vavr, fugue, and lambda.
This particular Either
is lightweight, and very easy to work with if you're already familiar with Optional
.
Sometimes, it can be desirable to put something into the "empty" value of an Optional
.
Let's call this "adding a Left value", since this value is no longer empty.
Adding a Left value is as easy as mapping with Either::right
,
followed by an orElseGet
to supply the Left value:
Either<String, BigInteger> possiblyPrime = Stream.generate(() ->
ThreadLocalRandom.current().nextInt(1000))
.map(BigInteger::valueOf)
.limit(10)
.filter(n -> n.isProbablePrime(10))
.findAny()
.<Either<String, BigInteger>>map(Either::right)
.orElseGet(() -> Either.left("no such value"));
Declaring the result type before the map
operation is necessary, due to limitations of Java's typechecker.
An Either has the familiar methods map
, flatMap
and filter
.
All of these work on Right Eithers, and leave a Left unchanged.
This is intuitive, because the corresponding methods in Optional
leave empty unchanged.
Symmetrically there are mapLeft
, flatMapLeft
and filterLeft
, which leave a Right unchanged instead.
Finally there is ifPresentOrElse ifLeftOrElse
(1.3) and the all-powerful fold
method,
as well as getRight
and getLeft
to convert back to Optional
.
If you have a stream of Either
, you can search for failures using one of the collectors
toValidList
and toValidListAll
:
Either<BigInteger, List<BigInteger>> twoPrimesOrOneComposite = Stream.generate(() ->
ThreadLocalRandom.current().nextInt(1000))
.map(BigInteger::valueOf)
.limit(2)
.<Either<BigInteger, BigInteger>>map(n -> n.isProbablePrime(10) ?
Either.right(n) : Either.left(n))
.collect(Eithers.toValidList());
This library grew for several months as part of the jbock project,
until it was released independently. jbock uses it internally to perform input validation,
and its generated parse
method returns an Either
.