在Java 8中是否有相当于Scala的Either?

时间:2014-10-02 13:55:01

标签: java scala java-8

就像Java 8中的java.util.Optional<T>(某种程度上)与Scala的Option[T]类型相同,是否与Scala的Either[L, R]相当?

8 个答案:

答案 0 :(得分:55)

没有Either类型是Java 8,因此您需要自己创建一个或使用某个第三方库。

您可以使用新的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; };
    }
}

只需在两个工厂方法的开头插入null,就可以很容易地将其更改为严格拒绝Objects.requireNonNull(value)。同样,添加对空的支持也是可以想象的。

答案 1 :(得分:22)

Atlassian Fugue。那里有Either的良好实施。

答案 2 :(得分:17)

在撰写本文时,vavr(以前称为javaslang)可能是最受欢迎的Java 8函数库。它与lambda-companion非常类似,或者在我的另一个答案中。

Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();

答案 3 :(得分:16)

Java标准库中没有Either。但是,Either中有FunctionalJava的实现,以及许多其他好的类。

答案 4 :(得分:7)

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可以作为一个或一个元组。

  • 披露我是独眼巨人反应的作者。

答案 5 :(得分:5)

lambda-companionEither类型(以及其他一些功能类型,例如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())

答案 6 :(得分:4)

不,没有。

Java语言开发人员明确声明像Option<T>这样的类型只能用作临时值(例如在流操作结果中),所以当他们 时与其他类似语言,它们不应该使用,因为它们在其他语言中使用。因此,没有Either这样的东西就不足为奇了,因为它不会像Optional那样自然地(例如来自流操作)出现。

答案 7 :(得分:4)

在一个小型图书馆中有Either的独立实现,&#34;矛盾&#34;:http://github.com/poetix/ambivalence

你可以从Maven中心获得它:

<dependency>
    <groupId>com.codepoetics</groupId>
    <artifactId>ambivalence</artifactId>
    <version>0.2</version>
</dependency>