ความแตกต่างระหว่างสองวิธีนี้: Optional.flatMap()
และOptional.map()
?
ตัวอย่างจะได้รับการชื่นชม
Stream#flatMap
Optional#flatMap
ความแตกต่างระหว่างสองวิธีนี้: Optional.flatMap()
และOptional.map()
?
ตัวอย่างจะได้รับการชื่นชม
Stream#flatMap
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>
มันเป็นองค์ประกอบของสองสำนวนการทำงาน: และmap
flatten
หมายเหตุ: - ด้านล่างเป็นภาพประกอบของแผนที่และฟังก์ชั่น flatmap มิฉะนั้นเป็นตัวเลือกที่ได้รับการออกแบบมาเพื่อใช้เป็นประเภทผลตอบแทนเท่านั้น
ตามที่คุณทราบแล้วว่าตัวเลือกเป็นคอนเทนเนอร์ชนิดหนึ่งซึ่งอาจมีหรือไม่มีวัตถุเดียวดังนั้นจึงสามารถใช้งานได้ทุกที่ที่คุณคาดว่าจะมีค่า Null (คุณอาจไม่เคยเห็น NPE หากใช้อุปกรณ์เสริมอย่างเหมาะสม) ตัวอย่างเช่นหากคุณมีวิธีการที่คาดว่าวัตถุบุคคลซึ่งอาจเป็นโมฆะคุณอาจต้องการเขียนวิธีดังนี้:
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
}
ในกรณีนี้ฟังก์ชั่นการเรียกใช้แผนที่จะห่อค่าที่ส่งคืนในตัวเลือกและให้ผลเช่น:
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; อย่าเรียกวิธีรับ (ถ้าคุณต้องการ) บนตัวเลือกโดยไม่ต้องตรวจสอบด้วย isPresent () เว้นแต่คุณจะอยู่ไม่ได้หากไม่มี NullPointerExceptions
Person
Optional
มันเป็นกับความตั้งใจของ API ที่จะใช้Optional
ในสมาชิกเช่นนี้ - ดูmail.openjdk.java.net/pipermail/jdk8-dev/2013-September/...
สิ่งที่ช่วยฉันได้คือดูซอร์สโค้ดของทั้งสองฟังก์ชัน
แผนที่ - ล้อมรอบผลลัพธ์ในตัวเลือก
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
ฟังก์ชั่น mapper wraps วัตถุแมปในOptional
ขณะที่map
ตัวเอง wraps Optional
วัตถุใน
Optional.map()
:ใช้ทุกองค์ประกอบและถ้ามีค่ามันจะถูกส่งไปยังฟังก์ชัน:
Optional<T> optionalValue = ...;
Optional<Boolean> added = optionalValue.map(results::add);
ตอนนี้เพิ่มมีหนึ่งในสามค่า: 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>
ชนิดเป็นชนิดส่งคืน
ตกลง. คุณจะต้องใช้ 'flatMap' เมื่อคุณกำลังเผชิญ optionals นี่คือตัวอย่าง
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); // ②
}
}
เช่นเดียวกับกระแสข้อมูล # แผนที่ตัวเลือกจะส่งคืนค่าที่ห่อหุ้มด้วยทางเลือก นั่นเป็นเหตุผลที่เราได้รับที่ซ้อนกันเป็นตัวเลือก Optional<Optional<Insurance>
- และที่②เราต้องการแมปเป็นอินสแตนซ์ประกันภัยนั่นคือสิ่งที่เกิดขึ้นกับโศกนาฏกรรม รูตซ้อนซ้อนกันเป็นตัวเลือก หากเราสามารถรับค่าหลักโดยไม่คำนึงถึงเชลล์เราจะทำให้เสร็จ นั่นคือสิ่งที่ flatMap ทำ
public Optional<String> getCarInsuranceName(Person person) {
return person.getOptionalCar()
.flatMap(Car::getOptionalInsurance)
.map(Insurance::getName);
}
ในท้ายที่สุดฉันขอแนะนำJava 8 In Actionแก่คุณหากคุณต้องการศึกษา Java8 อย่างเป็นระบบ