Is there an equivalent of Scala's Either in Java 8?
JavaScalaJava 8Java Problem Overview
Just like java.util.Optional<T>
in Java 8 is (somewhat) equivalent to Scala's Option[T]
type, is there an equivalent to Scala's Either[L, R]
?
Java Solutions
Solution 1 - Java
There is no Either
type is Java 8, so you need to create one yourself or use some third-party library.
You may build such a feature using the new Optional
type (but read to the end of this answer):
final class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(Optional.of(value), Optional.empty());
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left=l;
right=r;
}
public <T> T map(
Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc)
{
return left.<T>map(lFunc).orElseGet(()->right.map(rFunc).get());
}
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc)
{
return new Either<>(left.map(lFunc),right);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> rFunc)
{
return new Either<>(left, right.map(rFunc));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc)
{
left.ifPresent(lFunc);
right.ifPresent(rFunc);
}
}
Example use case:
new Random().ints(20, 0, 2).mapToObj(i -> (Either<String,Integer>)(i==0?
Either.left("left value (String)"):
Either.right(42)))
.forEach(either->either.apply(
left ->{ System.out.println("received left value: "+left.substring(11));},
right->{ System.out.println("received right value: 0x"+Integer.toHexString(right));}
));
In retrospective, the Optional
based solution is more like an academic example, but not a recommended approach. One problem is the treatment of null
as “empty” which contradicts the meaning of “either”.
The following code shows an Either
that considers null
a possible value, so it’s strictly “either”, left or right, even if the value is null
:
abstract class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<L,R>() {
@Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return lFunc.apply(value);
}
};
}
public static <L,R> Either<L,R> right(R value) {
return new Either<L,R>() {
@Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return rFunc.apply(value);
}
};
}
private Either() {}
public abstract <T> T map(
Function<? super L, ? extends T> lFunc, Function<? super R, ? extends T> rFunc);
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc) {
return this.<Either<T,R>>map(t -> left(lFunc.apply(t)), t -> (Either<T,R>)this);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> lFunc) {
return this.<Either<L,T>>map(t -> (Either<L,T>)this, t -> right(lFunc.apply(t)));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc) {
map(consume(lFunc), consume(rFunc));
}
private <T> Function<T,Void> consume(Consumer<T> c) {
return t -> { c.accept(t); return null; };
}
}
It’s easy to change that to a strict rejection of null
by simply inserting an Objects.requireNonNull(value)
at the beginning of both factory methods. Likewise, adding support for an empty either would be imaginable.
Solution 2 - Java
At the time of writing, vavr (formerly javaslang) is probably the most popular functional Java 8 library. It is pretty similar to lambda-companion's Either in my other answer.
Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();
Solution 3 - Java
There is no Either in the Java Standard Library. However there is an implementation of Either in FunctionalJava, along with many other nice classes.
Solution 4 - Java
cyclops-react has a 'right' biased either implementation called Xor.
Xor.primary("hello")
.map(s->s+" world")
//Primary["hello world"]
Xor.secondary("hello")
.map(s->s+" world")
//Secondary["hello"]
Xor.secondary("hello")
.swap()
.map(s->s+" world")
//Primary["hello world"]
Xor.accumulateSecondary(ListX.of(Xor.secondary("failed1"),
Xor.secondary("failed2"),
Xor.primary("success")),
Semigroups.stringConcat)
//failed1failed2
There is also a related type Ior which can act as an either or a tuple2.
- disclosure I am the author of cyclops-react.
Solution 5 - Java
No, there is none.
Java language developers explicitly state that types like Option<T>
are intended to be used only as temporary values (e.g. in stream operations results), so while they are the same thing as in other languages, they are not supposed to be used as they are used in other languages. So it is not surprising that there is no such thing as Either
because it does not arise naturally (e.g. from stream operations) like Optional
does.
Solution 6 - Java
There is a stand-alone implementation of Either
in a small library, "ambivalence": http://github.com/poetix/ambivalence
You can get it from Maven central:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
Solution 7 - Java
lambda-companion has an Either
type (and a few other functional types e.g. Try
)
<dependency>
<groupId>no.finn.lambda</groupId>
<artifactId>lambda-companion</artifactId>
<version>0.25</version>
</dependency>
Using it is easy:
final String myValue = Either.right("example").fold(failure -> handleFailure(failure), Function.identity())