在 Java 8 中是否有与 Scala 的任何等价物?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26162407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there an equivalent of Scala's Either in Java 8?
提问by HRJ
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.util.Optional<T>
在 Java 8 中(有点)等价于 Scala 的Option[T]
类型一样,是否有等价于 Scala 的类型Either[L, R]
?
采纳答案by Holger
There is no Either
type is Java?8, so you need to create one yourself or use some third-party library.
没有Either
类型是Java?8,所以你需要自己创建一个或者使用一些第三方库。
You may build such a feature using the new Optional
type (but read to the end of this answer):
您可以使用新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);
}
}
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”.
回想起来,Optional
基于解决方案更像是一个学术示例,而不是推荐的方法。一个问题是null
“空”的处理,这与“要么”的含义相矛盾。
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
:
下面的代码显示了一个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; };
}
}
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.
null
通过简单地Objects.requireNonNull(value)
在两个工厂方法的开头插入一个,很容易将其更改为严格拒绝。同样,可以想象添加对空值的支持。
回答by Vladimir Matveev
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 arethe same thing as in other languages, they are not supposedto 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.
Java 语言开发人员明确声明,like 类型Option<T>
仅用作临时值(例如在流操作结果中),因此虽然它们与其他语言中的相同,但不应像在其他语言中那样使用它们语言。因此,没有这样的事情并不奇怪,Either
因为它不像自然发生(例如从流操作)Optional
。
回答by Ravi Kiran
There is no Either in the Java Standard Library. However there is an implementation of Eitherin FunctionalJava, along with many other nice classes.
Java 标准库中没有任何一个。然而,在FunctionalJava 中有一个That的实现,以及许多其他不错的类。
回答by ZhekaKozlov
See Atlassian Fugue. There is a good implementation of Either
there.
参见Atlassian Fugue。那里有一个很好的实现Either
。
回答by Dominic Fox
There is a stand-alone implementation of Either
in a small library, "ambivalence": http://github.com/poetix/ambivalence
Either
在一个小库中有一个独立的实现,“矛盾”:http: //github.com/poetix/ambivalence
You can get it from Maven central:
您可以从 Maven 中心获取它:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
回答by whirlwin
lambda-companionhas an Either
type (and a few other functional types e.g. Try
)
lambda-companion有一个Either
类型(和一些其他的函数类型,例如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())
回答by whirlwin
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.
在撰写本文时,vavr(以前称为 javaslang)可能是最受欢迎的 Java 8 函数库。它与我的另一个答案中的 lambda-companion 非常相似。
Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();
回答by John McClean
cyclops-reacthas a 'right' biased either implementation called Xor.
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
There is also a related type Iorwhich can act as an either or a tuple2.
还有一个相关的类型Ior的可作为任一或tuple2行动。
- disclosure I am the author of cyclops-react.
- 披露我是独眼巨人反应的作者。