これら2つの方法の違いは何ですか:Optional.flatMap()
およびOptional.map()
?
例をいただければ幸いです。
Stream#flatMap
で1対1の対応をとっていませんOptional#flatMap
。
これら2つの方法の違いは何ですか:Optional.flatMap()
およびOptional.map()
?
例をいただければ幸いです。
Stream#flatMap
で1対1の対応をとっていませんOptional#flatMap
。
回答:
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);
}
どちらの印刷ステートメントも同じものを印刷します。
[flat]Map
マッピング関数をinput == null
?私の理解は、Optional
それがない場合のソートカットです-[JavaDoc](docs.oracle.com/javase/8/docs/api/java/util/…)はこれを裏付けているようです-" 値が存在する場合は、適用してください。 ……」
Optional.of(null)
はException
です。Optional.ofNullable(null) == Optional.empty()
。
どちらもオプションのタイプから何かに機能を引き受けます。
map()
「関数を適用しているとして、あなたが持っているオプションに」:
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
。
注:-以下は、mapおよびflatmap関数の図です。それ以外の場合、Optionalは主に戻り値の型としてのみ使用されるように設計されています。
ご存じのとおり、Optionalは単一のオブジェクトを含む場合と含まない場合があるコンテナの一種であるため、null値が予想される場所であればどこでも使用できます(Optionalを適切に使用すると、NPEが表示されない場合があります)。たとえば、null可能である可能性があるpersonオブジェクトを予期するメソッドがある場合、次のようなメソッドを記述できます。
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
}
ここでは、オプションの型に自動的にラップされる文字列型を返しました。
人物クラスがこのようになった場合、つまり電話もオプションです
class Person{
private Optional<String> phone;
//setter,getter
}
この場合、map関数を呼び出すと、戻り値が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メソッドを(必要な場合に)呼び出さないでください。
Person
が誤用されてOptional
いるため、回答の性質を混乱させる可能性があると思います。Optional
このようなメンバーで使用するAPIの意図に反しています-mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…を
私を助けたのは、2つの関数のソースコードを確認したことです。
マップ -結果をオプションでラップします。
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-「生の」オブジェクトを返します
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
}
}
flatMap
「生のオブジェクトを返す」とはどういう意味ですか?flatMap
また、「ラップされた」マッピング済みオブジェクトをで返しますOptional
。違いは、の場合とでflatMap
、マッパー機能でマッピングされたオブジェクトをラップOptional
しながら、map
それ自体が内のオブジェクトをラップしますOptional
。
Optional.map()
:すべての要素を受け取り、値が存在する場合は、関数に渡されます。
Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
今追加は:3つの値のいずれかがあるtrue
かfalse
に包まれたオプションの場合は、optionalValue
存在していた、または空のオプションをそう。
単純に使用できる結果を処理する必要がない場合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()
、結果は空です。
Optional<Double>
戻り値の型として型があるからです。
はい。あなたは、あなたがネストされたOptionalsに直面している場合にのみ使用「flatMap」に必要。これがその例です。
public class Person {
private Optional<Car> optionalCar;
public Optional<Car> getOptionalCar() {
return optionalCar;
}
}
public class Car {
private Optional<Insurance> optionalInsurance;
public Optional<Insurance> getOptionalInsurance() {
return optionalInsurance;
}
}
public class Insurance {
private String name;
public String getName() {
return name;
}
}
public class Test {
// map cannot deal with nested Optionals
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.map(Car::getOptionalInsurance) // ① leads to a Optional<Optional<Insurance>
.map(Insurance::getName); // ②
}
}
Streamと同様に、Optional#mapはOptionalでラップされた値を返します。これが、入れ子になったOptional-を取得する理由Optional<Optional<Insurance>
です。そして②では、それを保険インスタンスとしてマッピングしたいと思います。それが悲劇が起こった方法です。ルートはネストされたオプションです。シェルに関係なくコア値を取得できる場合は、それを実行します。それがflatMapが行うことです。
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.flatMap(Car::getOptionalInsurance)
.map(Insurance::getName);
}
結局のところ、Java8を体系的に研究したい場合は、Java 8 In Actionのみを推奨します。