जावा 8 - Optional.flatMap और Optional.map के बीच अंतर


162

इन दोनों विधियों में क्या अंतर है: Optional.flatMap()औरOptional.map() ?

एक उदाहरण की सराहना की जाएगी।



5
@AlexisC। आपका लिंक स्ट्रीम के नक्शे और फ्लैट मैप के बारे में है, न कि वैकल्पिक।
एर

1
@ यह कोई फर्क नहीं पड़ता, यदि आप समझते हैं कि मैप / फ्लैटपाइप कैसे काम करता है, तो यह स्ट्रीम के लिए है या नहीं, यह एक वैकल्पिक के लिए समान है। यदि op समझ गया कि यह स्ट्रीम के लिए कैसे काम करता है, तो उसे यह प्रश्न नहीं करना चाहिए। अवधारणा एक ही है।
एलेक्सिस सी।

2
@AlexisC। ज़रुरी नहीं। स्ट्रीम के फ्लैट मैप के साथ वैकल्पिक के फ्लैटपैप बहुत कम हैं।
एर

1
@Eran मैं के बारे में बात कर रहा हूँ वैचारिक मानचित्र और एक flatMap के बीच का अंतर, मैं के बीच एक-से-एक correspondance बनाने नहीं कर रहा हूँ Stream#flatMapऔर Optional#flatMap
एलेक्सिस सी।

जवाबों:


166

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);
}

दोनों प्रिंट स्टेटमेंट एक ही बात को प्रिंट करते हैं।


5
प्रश्न: [flat]Mapकभी ए के साथ मैपिंग फ़ंक्शन को कहेंगे input == null? मेरी समझ यह है कि Optionalयदि यह अनुपस्थित है तो शॉर्टकट्स - [JavaDoc] ( docs.oracle.com/javase/8/docs/api/java/util/… ) इसे बैक अप लगता है - " यदि कोई मान मौजूद है, तो लागू करें .." । "
बोरिस द स्पाइडर

1
@BoristheSpider Optional.of (null)! = Optional.empty ()
डिएगो मार्टिनो

14
@DiegoMartinoia Optional.of(null)एक है ExceptionOptional.ofNullable(null) == Optional.empty()
बोरिस स्पाइडर

1
@BoristheSpider हाँ, आप सही हैं,। मैं आपके प्रश्न का उत्तर देने की कोशिश कर रहा था, लेकिन मुझे लगता है कि मैंने इसे और भी अस्पष्ट बना दिया: वैचारिक रूप से, Optional.ofNullable (शून्य) खाली नहीं होना चाहिए, लेकिन व्यवहार में इसे माना जाता है, और इसलिए मैप / फ्लैटमैप निष्पादित नहीं करता है।
डिएगो मार्टिनो

1
मुझे लगता है कि इनपुट को कभी भी सुस्त नहीं होना चाहिए या प्राप्त करें या प्राप्त करें
ड्यूटालबर्के

55

वे दोनों वैकल्पिक के प्रकार से कुछ के लिए एक फ़ंक्शन लेते हैं।

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


7

नोट: - नीचे नक्शा और फ्लैटमैप फ़ंक्शन का चित्रण है, अन्यथा वैकल्पिक रूप से केवल रिटर्न प्रकार के रूप में उपयोग करने के लिए डिज़ाइन किया गया है।

जैसा कि आप पहले से ही जानते होंगे कि ऑप्शनल एक तरह का कंटेनर होता है जिसमें एक भी ऑब्जेक्ट नहीं हो सकता है या नहीं, इसलिए इसका उपयोग आप कहीं भी कर सकते हैं जहाँ आप एक शून्य मान की आशा करते हैं (यदि आप वैकल्पिक रूप से ठीक से उपयोग करते हैं तो आप कभी भी एनपीई नहीं देख सकते हैं)। उदाहरण के लिए यदि आपके पास एक ऐसी विधि है जो किसी व्यक्ति वस्तु की अपेक्षा करती है जो अशक्त हो सकती है, तो आप विधि को कुछ इस तरह लिखना चाहते हैं:

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));
}

पुनश्च; जब तक आप NullPointerException के बिना नहीं रह सकते, तब तक इसे वैकल्पिक () के साथ चेक किए बिना वैकल्पिक तरीके से कॉल करें।


1
मुझे लगता है कि यह उदाहरण आपके उत्तर की प्रकृति से विचलित होने की संभावना है क्योंकि आपकी कक्षा Personदुरुपयोग कर रही है Optional। यह Optionalइस तरह से सदस्यों पर उपयोग करने के लिए एपीआई के इरादे के खिलाफ है - देखें mail.openjdk.java.net/pipermail/jdk8-dev/2013-Seture/…
8bitjunkie

@ 8bitjunkie इस बात की ओर इशारा करने के लिए धन्यवाद, यह स्काला के विकल्प से अलग है ..
संदीपगौड़ा

6

दो कार्यों के स्रोत कोड पर एक नज़र डालने में मुझे क्या मदद मिली।

मानचित्र - एक वैकल्पिक में परिणाम को लपेटता है।

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
    }
}

1
flatMap"कच्ची 'वस्तु" रिटर्न "से आपका क्या तात्पर्य है ? flatMapमैप की गई वस्तु को "लिपटे" में भी लौटाता है Optional। अंतर यह है कि के मामले में flatMap, मैपर फ़ंक्शन मैप की गई वस्तु को लपेटता है Optionalजबकि mapस्वयं ऑब्जेक्ट को लपेटता है Optional
डेरेक महार

@DerekMahar ने मेरा डिलीट कर दिया, इसे दोबारा पोस्ट करने की जरूरत नहीं है, क्योंकि आपने अपनी टिप्पणी सही संपादित की है।
मैक्सएक्स

3
  • 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(), परिणाम खाली है।


1
यह संकलन नहीं है। आपके दोनों एक्सप्रेशंस डबल के बजाय एक वैकल्पिक <डबल> लौटाते हैं, जिसके परिणाम आप बता रहे हैं।
JL_SO

@JL_SO आप सही हैं। क्योंकि व्युत्क्रम Optional<Double>में रिटर्न टाइप के रूप में टाइप होता है।
naj_art

3

ठीक है। आप केवल जब तुम नेस्टेड 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);       // ②
    }

}

स्ट्रीम की तरह, वैकल्पिक # मानचित्र एक वैकल्पिक द्वारा लिपटे मान को लौटाएगा। इसलिए हमें एक नेस्टेड ऑप्शनल मिलता है - Optional<Optional<Insurance>। और we पर, हम इसे एक बीमा उदाहरण के रूप में मैप करना चाहते हैं, इसी तरह यह त्रासदी हुई है। रूट नेस्टेड ऑप्शनल है। यदि हम गोले की परवाह किए बिना मुख्य मूल्य प्राप्त कर सकते हैं, तो हम इसे पूरा कर लेंगे। यही फ्लैटप्लेट करता है।

public Optional<String> getCarInsuranceName(Person person) {
    return person.getOptionalCar()
                 .flatMap(Car::getOptionalInsurance)
                 .map(Insurance::getName);
}

अंत में, मैंने आपको जावा 8 इन एक्शन के बारे में बताया, यदि आप Java8 को व्यवस्थित रूप से अध्ययन करना चाहते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.