@AlexisC. Tautan Anda adalah tentang peta Stream dan flatMap, bukan Opsional.
Eran
1
@Ran Itu tidak masalah, jika Anda memahami cara kerja peta / flatMap apakah itu untuk Stream atau tidak, itu sama untuk Opsional. Jika op mengerti cara kerjanya untuk Stream, maka dia seharusnya tidak menanyakan pertanyaan ini. Konsepnya sama.
Alexis C.
2
@AlexisC. Tidak juga. FlatMap opsional memiliki sedikit kesamaan dengan flatMap Stream.
Eran
1
@Ran saya berbicara tentang perbedaan konseptual antara peta dan flatMap, saya tidak membuat korespondensi satu-ke-satu antara Stream#flatMapdan Optional#flatMap.
Alexis C.
Jawaban:
166
Gunakan mapjika fungsi mengembalikan objek yang Anda butuhkan atau flatMapjika fungsi mengembalikan sebuah Optional. Sebagai contoh:
publicstaticvoid main(String[] args){Optional<String> s =Optional.of("input");System.out.println(s.map(Test::getOutput));System.out.println(s.flatMap(Test::getOutputOpt));}staticString getOutput(String input){return input ==null?null:"output for "+ input;}staticOptional<String> getOutputOpt(String input){return input ==null?Optional.empty():Optional.of("output for "+ input);}
Pertanyaan: apakah akan [flat]Mappernah memanggil fungsi pemetaan dengan input == null? Pemahaman saya adalah bahwa Optionalsortcuts jika tidak ada - [ JavaDoc ] ( docs.oracle.com/javase/8/docs/api/java/util/… ) tampaknya mendukung hal ini - " Jika suatu nilai hadir, terapkan .. . "
@DiegoMartinoia Optional.of(null)adalah seorang Exception. Optional.ofNullable(null) == Optional.empty().
Boris the Spider
1
@ BoristheSpider ya, Anda benar ,. Saya mencoba untuk menjawab pertanyaan Anda, tetapi saya rasa saya membuatnya lebih tidak jelas: secara konseptual, Opsional. Tidak dapat dibatalkan (nol) TIDAK boleh kosong, tetapi dalam praktiknya dianggap demikian, dan oleh karena itu peta / flatmap tidak dieksekusi.
Diego Martinoia
1
Saya pikir input tidak boleh nol di getOutputOpt atau getOutput
DanyalBurke
55
Mereka berdua mengambil fungsi dari jenis opsional ke sesuatu.
map()menerapkan fungsi " apa adanya " pada opsional yang Anda miliki:
Apa yang terjadi jika fungsi Anda berasal dari fungsi T -> Optional<U>?
Hasil Anda sekarang adalah Optional<Optional<U>>!
Tentang apa flatMap()itu: jika fungsi Anda sudah mengembalikan Optional, flatMap()sedikit lebih pintar dan tidak membungkusnya dua kali, kembali Optional<U>.
Ini komposisi dari dua idiom fungsional: mapdan flatten.
Catatan: - di bawah ini adalah ilustrasi fungsi peta dan flatmap, jika tidak, Opsional utamanya dirancang untuk digunakan sebagai tipe pengembalian saja.
Seperti yang sudah Anda ketahui, Opsional adalah sejenis wadah yang mungkin atau mungkin tidak mengandung satu objek, sehingga dapat digunakan di mana pun Anda mengantisipasi nilai nol (Anda mungkin tidak pernah melihat NPE jika menggunakan Opsional dengan benar). Sebagai contoh jika Anda memiliki metode yang mengharapkan objek orang yang dapat dibatalkan, Anda mungkin ingin menulis metode seperti ini:
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));}classPerson{privateString phone;//setter, getters}
Di sini Anda telah mengembalikan jenis String yang secara otomatis dibungkus dengan jenis Opsional.
Jika kelas orang terlihat seperti ini, yaitu ponsel juga Opsional
Dalam hal ini, memohon fungsi peta akan membungkus nilai yang dikembalikan dalam Opsional dan menghasilkan sesuatu seperti:
Optional<Optional<String>>//And you may want Optional<String> instead, here comes flatMapvoid doSome(Optional<Person> person){Optional<String> phone = person.flatMap((p)->p.getPhone());
phone.ifPresent((ph)->dial(ph));}
PS; Jangan pernah panggil metode get (jika perlu) pada Opsional tanpa memeriksanya dengan isPresent () kecuali Anda tidak dapat hidup tanpa NullPointerExceptions.
Saya pikir contoh ini cenderung mengalihkan perhatian dari sifat jawaban Anda karena kelas Anda Personmenyalahgunakan Optional. Adalah bertentangan dengan niat API untuk menggunakan Optionalanggota seperti ini - lihat mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…
8bitjunkie
@ 8bitjunkie Terima kasih telah menunjukkan hal itu, ini berbeda dari Opsi Scala ..
SandeepGodara
6
Apa yang membantu saya adalah melihat kode sumber dari kedua fungsi tersebut.
Peta - membungkus hasilnya dalam Opsional.
public<U>Optional<U> map(Function<?super T,?extends U> mapper){Objects.requireNonNull(mapper);if(!isPresent())return empty();else{returnOptional.ofNullable(mapper.apply(value));//<--- wraps in an optional}}
Apa yang Anda maksud dengan flatMap"mengembalikan objek 'mentah'"? flatMapjuga mengembalikan objek yang dipetakan "terbungkus" dalam Optional. Perbedaannya adalah bahwa dalam kasus flatMap, fungsi mapper membungkus objek yang dipetakan Optionalsementara mapitu sendiri membungkus objek Optional.
Derek Mahar
@DerekMahar menghapus milik saya, tidak perlu memposting ulang, karena Anda telah mengedit komentar Anda dengan benar.
maxxyme
3
Optional.map():
Mengambil setiap elemen dan jika nilainya ada, ia diteruskan ke fungsi:
Sekarang ditambahkan memiliki salah satu dari tiga nilai: trueatau falsedibungkus menjadi Opsional , jika optionalValueada, atau Opsional kosong sebaliknya.
Jika Anda tidak perlu memproses hasil yang hanya dapat Anda gunakan ifPresent(), itu tidak memiliki nilai kembali:
optionalValue.ifPresent(results::add);
Optional.flatMap():
Bekerja serupa dengan metode stream yang sama. Ratakan aliran sungai. Dengan perbedaan bahwa jika nilai disajikan itu diterapkan pada fungsi. Kalau tidak, opsional kosong dikembalikan.
Anda dapat menggunakannya untuk membuat panggilan fungsi nilai opsional.
Misalkan kita memiliki metode:
publicstaticOptional<Double> inverse(Double x){return x ==0?Optional.empty():Optional.of(1/ x);}publicstaticOptional<Double> squareRoot(Double x){return x <0?Optional.empty():Optional.of(Math.sqrt(x));}
Kemudian Anda dapat menghitung akar kuadrat dari invers, seperti:
Optional<Double> result = inverse(-4.0).flatMap(MyMath::squareRoot);
atau, jika Anda lebih suka:
Optional<Double> result =Optional.of(-4.0).flatMap(MyMath::inverse).flatMap(MyMath::squareRoot);
Jika salah satu inverse()atau squareRoot()mengembalikan Optional.empty(), hasilnya kosong.
Ini tidak dikompilasi. Kedua ekspresi Anda menghasilkan Opsional <Double> daripada Double yang Anda tetapkan hasilnya.
JL_SO
@ JL_SO Anda benar. Karena terbalik memiliki Optional<Double>tipe sebagai tipe pengembalian.
nazar_art
3
Baik. Anda hanya perlu menggunakan 'flatMap' ketika Anda menghadapi Opsional bersarang . Inilah contohnya.
publicclassPerson{privateOptional<Car> optionalCar;publicOptional<Car> getOptionalCar(){return optionalCar;}}publicclassCar{privateOptional<Insurance> optionalInsurance;publicOptional<Insurance> getOptionalInsurance(){return optionalInsurance;}}publicclassInsurance{privateString name;publicString getName(){return name;}}publicclassTest{// map cannot deal with nested OptionalspublicOptional<String> getCarInsuranceName(Person person){return person.getOptionalCar().map(Car::getOptionalInsurance)// ① leads to a Optional<Optional<Insurance>.map(Insurance::getName);// ②}}
Seperti Stream, peta # Opsional akan mengembalikan nilai yang dibungkus oleh Opsional. Itu sebabnya kami mendapatkan Opsional bersarang - Optional<Optional<Insurance>. Dan di ②, kami ingin memetakannya sebagai contoh Asuransi, begitulah tragedi itu terjadi. Akar bersarang Opsional. Jika kami bisa mendapatkan nilai inti terlepas dari cangkang, kami akan menyelesaikannya. Itulah yang dilakukan flatMap.
Stream#flatMap
danOptional#flatMap
.Jawaban:
Gunakan
map
jika fungsi mengembalikan objek yang Anda butuhkan atauflatMap
jika fungsi mengembalikan sebuahOptional
. Sebagai contoh:Kedua pernyataan cetak mencetak hal yang sama.
sumber
[flat]Map
pernah memanggil fungsi pemetaan denganinput == null
? Pemahaman saya adalah bahwaOptional
sortcuts jika tidak ada - [ JavaDoc ] ( docs.oracle.com/javase/8/docs/api/java/util/… ) tampaknya mendukung hal ini - " Jika suatu nilai hadir, terapkan .. . "Optional.of(null)
adalah seorangException
.Optional.ofNullable(null) == Optional.empty()
.Mereka berdua mengambil fungsi dari jenis opsional ke sesuatu.
map()
menerapkan fungsi " apa adanya " pada opsional yang Anda miliki:Apa yang terjadi jika fungsi Anda berasal dari fungsi
T -> Optional<U>
?Hasil Anda sekarang adalah
Optional<Optional<U>>
!Tentang apa
flatMap()
itu: jika fungsi Anda sudah mengembalikanOptional
,flatMap()
sedikit lebih pintar dan tidak membungkusnya dua kali, kembaliOptional<U>
.Ini komposisi dari dua idiom fungsional:
map
danflatten
.sumber
Catatan: - di bawah ini adalah ilustrasi fungsi peta dan flatmap, jika tidak, Opsional utamanya dirancang untuk digunakan sebagai tipe pengembalian saja.
Seperti yang sudah Anda ketahui, Opsional adalah sejenis wadah yang mungkin atau mungkin tidak mengandung satu objek, sehingga dapat digunakan di mana pun Anda mengantisipasi nilai nol (Anda mungkin tidak pernah melihat NPE jika menggunakan Opsional dengan benar). Sebagai contoh jika Anda memiliki metode yang mengharapkan objek orang yang dapat dibatalkan, Anda mungkin ingin menulis metode seperti ini:
Di sini Anda telah mengembalikan jenis String yang secara otomatis dibungkus dengan jenis Opsional.
Jika kelas orang terlihat seperti ini, yaitu ponsel juga Opsional
Dalam hal ini, memohon fungsi peta akan membungkus nilai yang dikembalikan dalam Opsional dan menghasilkan sesuatu seperti:
PS; Jangan pernah panggil metode get (jika perlu) pada Opsional tanpa memeriksanya dengan isPresent () kecuali Anda tidak dapat hidup tanpa NullPointerExceptions.
sumber
Person
menyalahgunakanOptional
. Adalah bertentangan dengan niat API untuk menggunakanOptional
anggota seperti ini - lihat mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/…Apa yang membantu saya adalah melihat kode sumber dari kedua fungsi tersebut.
Peta - membungkus hasilnya dalam Opsional.
flatMap - mengembalikan objek 'mentah'
sumber
flatMap
"mengembalikan objek 'mentah'"?flatMap
juga mengembalikan objek yang dipetakan "terbungkus" dalamOptional
. Perbedaannya adalah bahwa dalam kasusflatMap
, fungsi mapper membungkus objek yang dipetakanOptional
sementaramap
itu sendiri membungkus objekOptional
.Optional.map()
:Mengambil setiap elemen dan jika nilainya ada, ia diteruskan ke fungsi:
Sekarang ditambahkan memiliki salah satu dari tiga nilai:
true
ataufalse
dibungkus menjadi Opsional , jikaoptionalValue
ada, atau Opsional kosong sebaliknya.Jika Anda tidak perlu memproses hasil yang hanya dapat Anda gunakan
ifPresent()
, itu tidak memiliki nilai kembali:Optional.flatMap()
:Bekerja serupa dengan metode stream yang sama. Ratakan aliran sungai. Dengan perbedaan bahwa jika nilai disajikan itu diterapkan pada fungsi. Kalau tidak, opsional kosong dikembalikan.
Anda dapat menggunakannya untuk membuat panggilan fungsi nilai opsional.
Misalkan kita memiliki metode:
Kemudian Anda dapat menghitung akar kuadrat dari invers, seperti:
atau, jika Anda lebih suka:
Jika salah satu
inverse()
atausquareRoot()
mengembalikanOptional.empty()
, hasilnya kosong.sumber
Optional<Double>
tipe sebagai tipe pengembalian.Baik. Anda hanya perlu menggunakan 'flatMap' ketika Anda menghadapi Opsional bersarang . Inilah contohnya.
Seperti Stream, peta # Opsional akan mengembalikan nilai yang dibungkus oleh Opsional. Itu sebabnya kami mendapatkan Opsional bersarang -
Optional<Optional<Insurance>
. Dan di ②, kami ingin memetakannya sebagai contoh Asuransi, begitulah tragedi itu terjadi. Akar bersarang Opsional. Jika kami bisa mendapatkan nilai inti terlepas dari cangkang, kami akan menyelesaikannya. Itulah yang dilakukan flatMap.Pada akhirnya, saya merekomendasikan Java 8 In Action kepada Anda jika Anda ingin mempelajari Java8 secara sistematis.
sumber