web-dev-qa-db-ja.com

Java 8-Optional.flatmapとOptional.mapの違い

これら2つのメソッドOptional.flatMap()Optional.map()の違いは何ですか?

一例をいただければ幸いです。

119
codependent

関数が必要なオブジェクトを返す場合はmapを使用し、関数がflatMapを返す場合はOptionalを使用します。例えば:

public static void main(String[] args) {
  Optional<String> s = Optional.of("input");
  System.out.println(s.map(Test::getOutput));
  System.out.println(s.flatMap(Test::getOutputOpt));
}

static String getOutput(String input) {
  return input == null ? null : "output for " + input;
}

static Optional<String> getOutputOpt(String input) {
  return input == null ? Optional.empty() : Optional.of("output for " + input);
}

両方の印刷ステートメントは同じものを印刷します。

117
assylias

どちらもオプションのタイプから何かに機能を取ります。

map()は、オプションの「as(」を適用します:

if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));

関数がT -> Optional<U>の関数である場合はどうなりますか?
結果はOptional<Optional<U>>です!

flatMap()の目的は次のとおりです。関数が既にOptionalを返している場合、flatMap()は少し賢く、二重にラップせずにOptional<U>を返します。

これは、2つの機能的なイディオム、mapおよびflattenの構成です。

46
Diego Martinoia

注:-以下は、mapおよびflatmap関数の図です。それ以外の場合、Optionalは主に戻り値の型としてのみ使用されるように設計されています。

既にご存知かもしれませんが、Optionalは単一のオブジェクトを含む場合も含まない場合もある一種のコンテナーであるため、null値が予想される場所ならどこでも使用できます(Optionalを正しく使用すると、NPEが表示されない場合があります)。たとえば、nullを許可する人物オブジェクトを期待するメソッドがある場合、次のようなメソッドを記述できます。

void doSome(Optional<Person> person){
  /*and here you want to retrieve some property phone out of person
    you may write something like this:
  */
  Optional<String> phone = person.map((p)->p.getPhone());
  phone.ifPresent((ph)->dial(ph));
}
class Person{
  private String phone;
  //setter, getters
}

ここでは、オプションの型に自動的にラップされるString型を返しました。

個人クラスがこのように見える場合、つまり電話もオプションです

class Person{
  private Optional<String> phone;
  //setter,getter
}

この場合、マップ関数を呼び出すと、戻り値がOptionalにラップされ、次のような結果が得られます。

Optional<Optional<String>> 
//And you may want Optional<String> instead, here comes flatMap

void doSome(Optional<Person> person){
  Optional<String> phone = person.flatMap((p)->p.getPhone());
  phone.ifPresent((ph)->dial(ph));
}

PS; NullPointerExceptionsなしでは生きられない場合を除き、isPresent()でチェックせずにOptionalでgetメソッド(必要な場合)を呼び出さないでください。

6
SandeepGodara

私が役立ったのは、2つの関数のソースコードを見ていたことです。

Map-オプションで結果をラップします。

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value)); //<--- wraps in an optional
    }
}

flatMap-'raw'オブジェクトを返します

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value)); //<---  returns 'raw' object
    }
}
5
Robert Niestroj
  • Optional.map()

すべての要素を受け取り、値が存在する場合は、関数に渡されます。

Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);

現在、追加には3つの値のいずれかがあります:trueまたはfalseは、Optionalの場合、optionalValueまたは、empty Optional.

結果を処理する必要がない場合は、単にifPresent()を使用できますが、戻り値はありません。

optionalValue.ifPresent(results::add); 
  • Optional.flatMap()

ストリームの同じ方法と同様に機能します。ストリームのストリームを平坦化します。値が提示された場合、関数に適用されるという違いがあります。それ以外の場合、空のオプションが返されます。

オプションの値関数呼び出しの作成に使用できます。

メソッドがあるとします:

public static Optional<Double> inverse(Double x) {
    return x == 0 ? Optional.empty() : Optional.of(1 / x);
}

public static Optional<Double> squareRoot(Double x) {
    return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
}

次に、次のように逆行列の平方根を計算できます。

Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);

または、必要に応じて:

Optional<Double> result = Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);

inverse()またはsquareRoot()Optional.empty()を返す場合、結果は空です。

2
nazar_art