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

后端 未结 8 722
南旧
南旧 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:29

    lambda-companion has an Either type (and a few other functional types e.g. 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())
    
    0 讨论(0)
  • 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<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”.

    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<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.

    0 讨论(0)
  • 2020-11-28 23:37

    See Atlassian Fugue. There is a good implementation of Either there.

    0 讨论(0)
  • 2020-11-28 23:39

    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.

    Either<String,Integer> value = compute().right().map(i -> i * 2).toEither();
    
    0 讨论(0)
  • 2020-11-28 23:45

    There is a stand-alone implementation of Either in a small library, "ambivalence": http://github.com/poetix/ambivalence

    You can get it from Maven central:

    <dependency>
        <groupId>com.codepoetics</groupId>
        <artifactId>ambivalence</artifactId>
        <version>0.2</version>
    </dependency>
    
    0 讨论(0)
  • 2020-11-28 23:48

    cyclops-react has a 'right' biased either implementation called 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 Ior which can act as an either or a tuple2.

    • disclosure I am the author of cyclops-react.
    0 讨论(0)
提交回复
热议问题