The Either type is related to Optional, but can have different "failure" states, other than only empty.
Either can be used to collect error messages
or simply as a typed alternative to exceptions.
There are several popular libraries that offer an Either type,
including vavr, fugue, and lambda.
It can sometimes 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.
Going from Optional to Either is as easy as mapping with Either::right,
followed by 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() // Optional<BigInteger>
.<Either<String, BigInteger>>map(Either::right) // Optional<Either<String, BigInteger>>
.orElseGet(() -> Either.left("no such value")); // Either<String, BigInteger>Repeating the result type in the penultimate line is necessary, due to a limitation of Java's typechecker.
Either has the map and filter methods, which are familiar from Optional.
These return a Left value unchanged.
There is ifLeftOrElse and fold,
as well as getRightOrElseThrow() and getLeftOrElseThrow() to get the value.
Given a stream of eithers, you can use the built-in collectors
firstFailure or allFailures to search for Left values:
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.firstFailure());The jbock compiler uses either internally.