web-dev-qa-db-ja.com

Java 8にScalaのいずれかの同等物がありますか?

と同じように Java.util.Optional<T> in Java 8は(多少)ScalaのOption[T]タイプ、ScalaのEither[L, R]

66
HRJ

Java 8のEitherタイプはないため、自分で作成するか、サードパーティのライブラリを使用する必要があります。

新しい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ベースのソリューションは学術的な例に似ていますが、推奨されるアプローチではありません。 1つの問題は、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; };
    }
}
_

両方のファクトリメソッドの先頭にObjects.requireNonNull(value)を挿入するだけで、それをnullの厳密な拒否に簡単に変更できます。同様に、空のどちらかのサポートを追加することも考えられます。

57
Holger

Atlassian Fugue を参照してください。 Eitherの適切な実装があります。

22
ZhekaKozlov

執筆時点で、 vavr (以前のjavaslang)はおそらく最も人気のある機能的なJava 8ライブラリです。他の答えではlambda-companionのどちらかとかなり似ています。 。

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

Java Standard Libraryにはどちらもありません。ただし、他の多くのNiceクラスとともに、 FunctionalJavaEither の実装があります。

17
Ravi Kiran

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 もあり、これはTuple2としても機能します。

  • 開示私はc​​yclops-reactの著者です。
9
John McClean

lambda-companion にはEitherタイプ(および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())
5
whirlwin

小さなライブラリ "ambivalence"にはEitherのスタンドアロン実装があります。 http://github.com/poetix/ambivalence

Maven Centralから入手できます。

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

いいえ、ありません。

Java言語の開発者は、Option<T>は一時的な値としてのみ使用することを目的としているため(ストリーム操作の結果など)、areは他の言語と同じですが、想定外 to他の言語で使用されているように使用されます。したがって、Eitherのように自然に(たとえばストリーム操作から)発生しないため、Optionalのようなものがないことは驚くことではありません。

4