java - Java 8 中是否有等效于 Scala 的 Either?

标签 java scala java-8

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

最佳答案

没有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 视为“空”,这与“任一”的含义相矛盾。

以下代码显示了一个将 null 视为可能值的 Either,因此即使值为 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。同样,添加对空的任何一个的支持也是可以想象的。

关于java - Java 8 中是否有等效于 Scala 的 Either?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26162407/

相关文章:

java - 如何使用 java 8 流创建多个新的 Hashmap?

java - 通过 Eclipse 在 Docker 上调试 Wildfly 应用程序?

postgresql - 从 postgreSQL 读取 100M 行到 Spark 并写入 parquet

scala - 如何找到不会给出无限结果的最小 `Double` 除数?

java - 将 IntStream.iterate 限制为特定值

java - 如何从一个非常大的文件中读取行号 x 到 (x+y)

java - 从 Java 中的 HashMap 返回通配符匹配列表

java - boolean 函数返回无值

java - 加快我的 Java tcp 传输速度!

json - 提升-mongo-记录 : Empty JsonObjectField in mongo collection