Is there an equivalent of Scala's Either in Java 8?

后端 未结 8 795
南旧
南旧 2020-11-28 23:00

Just like java.util.Optional in Java 8 is (somewhat) equivalent to Scala\'s Option[T] type, is there an equivalent to Scala\'s Eithe

8条回答
  •  余生分开走
    2020-11-28 23:31

    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
    {
        public static  Either left(L value) {
            return new Either<>(Optional.of(value), Optional.empty());
        }
        public static  Either right(R value) {
            return new Either<>(Optional.empty(), Optional.of(value));
        }
        private final Optional left;
        private final Optional right;
        private Either(Optional l, Optional r) {
          left=l;
          right=r;
        }
        public  T map(
            Function lFunc,
            Function rFunc)
        {
            return left.map(lFunc).orElseGet(()->right.map(rFunc).get());
        }
        public  Either mapLeft(Function lFunc)
        {
            return new Either<>(left.map(lFunc),right);
        }
        public  Either mapRight(Function rFunc)
        {
            return new Either<>(left, right.map(rFunc));
        }
        public void apply(Consumer lFunc, Consumer rFunc)
        {
            left.ifPresent(lFunc);
            right.ifPresent(rFunc);
        }
    }
    

    Example use case:

    new Random().ints(20, 0, 2).mapToObj(i -> (Either)(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
    {
        public static  Either left(L value) {
            return new Either() {
                @Override public  T map(Function lFunc,
                                           Function rFunc) {
                    return lFunc.apply(value);
                }
            };
        }
        public static  Either right(R value) {
            return new Either() {
                @Override public  T map(Function lFunc,
                                           Function rFunc) {
                    return rFunc.apply(value);
                }
    
            };
        }
        private Either() {}
        public abstract  T map(
          Function lFunc, Function rFunc);
    
        public  Either mapLeft(Function lFunc) {
            return this.>map(t -> left(lFunc.apply(t)), t -> (Either)this);
        }
        public  Either mapRight(Function lFunc) {
            return this.>map(t -> (Either)this, t -> right(lFunc.apply(t)));
        }
        public void apply(Consumer lFunc, Consumer rFunc) {
            map(consume(lFunc), consume(rFunc));
        }
        private  Function consume(Consumer 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.

提交回复
热议问题