Apa perbedaan antara kedua metode ini: Optional.flatMap()
dan Optional.map()
?
Sebuah contoh akan dihargai.
Stream#flatMap
dan Optional#flatMap
.
Apa perbedaan antara kedua metode ini: Optional.flatMap()
dan Optional.map()
?
Sebuah contoh akan dihargai.
Stream#flatMap
dan Optional#flatMap
.
Jawaban:
Gunakan map
jika fungsi mengembalikan objek yang Anda butuhkan atau flatMap
jika fungsi mengembalikan sebuah Optional
. Sebagai contoh:
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);
}
Kedua pernyataan cetak mencetak hal yang sama.
[flat]Map
pernah memanggil fungsi pemetaan dengan input == null
? Pemahaman saya adalah bahwa Optional
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 seorang Exception
. Optional.ofNullable(null) == Optional.empty()
.
Mereka berdua mengambil fungsi dari jenis opsional ke sesuatu.
map()
menerapkan fungsi " apa adanya " pada opsional yang Anda miliki:
if (optional.isEmpty()) return Optional.empty();
else return Optional.of(f(optional.get()));
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: map
dan 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));
}
class Person{
private String 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
class Person{
private Optional<String> phone;
//setter,getter
}
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 flatMap
void 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.
Person
menyalahgunakan Optional
. Adalah bertentangan dengan niat API untuk menggunakan Optional
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.
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 - mengembalikan objek 'mentah'
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
"mengembalikan objek 'mentah'"? flatMap
juga mengembalikan objek yang dipetakan "terbungkus" dalam Optional
. Perbedaannya adalah bahwa dalam kasus flatMap
, fungsi mapper membungkus objek yang dipetakan Optional
sementara map
itu sendiri membungkus objek Optional
.
Optional.map()
:Mengambil setiap elemen dan jika nilainya ada, ia diteruskan ke fungsi:
Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
Sekarang ditambahkan memiliki salah satu dari tiga nilai: true
atau false
dibungkus menjadi Opsional , jika optionalValue
ada, 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:
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));
}
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.
Optional<Double>
tipe sebagai tipe pengembalian.
Baik. Anda hanya perlu menggunakan 'flatMap' ketika Anda menghadapi Opsional bersarang . Inilah contohnya.
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); // ②
}
}
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.
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.flatMap(Car::getOptionalInsurance)
.map(Insurance::getName);
}
Pada akhirnya, saya merekomendasikan Java 8 In Action kepada Anda jika Anda ingin mempelajari Java8 secara sistematis.