[英]Is there an equivalent of Scala's Either in Java 8?
就像 Java 8 java.util.Optional<T>
是(有点)等价于 Scala 的Option[T]
类型,是否有等价于 Scala 的Either[L, R]
?
Java 8 没有Either
类型,因此您需要自己创建一个或使用一些第三方库。
您可以使用新的Optional
类型构建这样的功能(但请阅读本答案的末尾):
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);
}
}
示例用例:
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));}
));
回想起来,基于Optional
的解决方案更像是一个学术示例,而不是推荐的方法。 一个问题是将null
视为“空”,这与“要么”的含义相矛盾。
下面的代码显示了Either
将null
视为一个可能值的或者,所以它是严格的“要么”,左或右,即使该值为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; };
}
}
通过简单地在两个工厂方法的开头插入一个Objects.requireNonNull(value)
,很容易将其更改为严格拒绝null
。 同样,添加对空的支持也是可以想象的。
在撰写本文时, vavr (以前称为 javaslang)可能是最受欢迎的 Java 8 函数库。 它与我的另一个答案中的 lambda-companion 非常相似。
Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();
见Atlassian Fugue 。 这是一个很好的实施Either
在那里。
Java 标准库中没有任何一个。 然而,在FunctionalJava 中有一个That的实现,以及许多其他不错的类。
cyclops-react有一个“正确”的偏向任一实现,称为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
还有一个相关的类型Ior的可作为任一或tuple2行动。
不,没有。
Java 语言开发人员明确声明像Option<T>
这样的类型仅用作临时值(例如在流操作结果中),因此虽然它们与其他语言中的相同,但它们不应该被用作它们用于其他语言。 因此,没有Either
这样的东西并不奇怪,因为它不像Optional
那样自然产生(例如来自流操作)。
有一个独立的实现Either
在一个小型图书馆,“矛盾”: http://github.com/poetix/ambivalence
您可以从 Maven 中心获取它:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
λ-伴侣具有Either
类型(和其他一些功能类型例如Try
)
<dependency>
<groupId>no.finn.lambda</groupId>
<artifactId>lambda-companion</artifactId>
<version>0.25</version>
</dependency>
使用它很容易:
final String myValue = Either.right("example").fold(failure -> handleFailure(failure), Function.identity())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.