स्ट्रीम के साथ जावा 8 के वैकल्पिक का उपयोग करना :: flatMap


240

नया जावा 8 स्ट्रीम फ्रेमवर्क और दोस्त कुछ बहुत ही संक्षिप्त जावा कोड के लिए बनाते हैं, लेकिन मैं एक सरल-सहज स्थिति में आया हूं जो संक्षिप्त रूप से करने के लिए मुश्किल है।

एक List<Thing> thingsविधि और विधि पर विचार करें Optional<Other> resolve(Thing thing)। मैं Thingएस को मैप करना चाहता हूं Optional<Other>और पहले प्राप्त करना चाहता हूं Other। स्पष्ट समाधान का उपयोग करना होगा things.stream().flatMap(this::resolve).findFirst(), लेकिन इसके लिए flatMapआवश्यक है कि आप एक स्ट्रीम लौटाएं, और Optionalइसके लिए कोई stream()विधि नहीं है (या यह Collectionएक विधि है या इसे रूपांतरित करने या इसे देखने के लिए एक विधि प्रदान करें Collection)।

सबसे अच्छा मैं यह कर सकता हूं:

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

लेकिन यह एक बहुत ही सामान्य मामले की तरह लगता है के लिए भयानक रूप से लंबे समय से लगता है। किसी को भी एक बेहतर विचार है?


आपके उदाहरण के साथ थोड़ा सा कोडिंग करने के बाद, मैं वास्तव में स्पष्ट संस्करण को एक से अधिक पठनीय मानता हूं, यदि यह मौजूद था, तो .flatMap(Optional::toStream)आपके संस्करण के साथ आप वास्तव में देखते हैं कि क्या चल रहा है।
स्किवि

19
@ एस्की वेल, जेडीके Optional.stream9 में अब मौजूद है ....
स्टुअर्ट मार्क्स

मैं उत्सुक हूं कि यह कहां से प्रलेखित है, और इसे प्राप्त करने के लिए क्या प्रक्रिया है। कुछ अन्य विधियां हैं जो वास्तव में ऐसा लगता है जैसे उन्हें अस्तित्व में होना चाहिए, और मैं उत्सुक हूं जहां एपीआई परिवर्तनों के लिए चर्चा हो रही है।
योना एप्लेट्री


10
मजेदार बात यह है कि JDK-8050820 वास्तव में अपने विवरण में इस प्रश्न को संदर्भित करता है!
डिडिएर एल

जवाबों:


265

जावा ९

Optional.stream JDK 9 में जोड़ा गया है। यह आपको किसी भी सहायक विधि की आवश्यकता के बिना, निम्नलिखित करने में सक्षम बनाता है:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(Optional::stream)
          .findFirst();

जावा 8

हां, यह एपीआई में एक छोटा सा छेद था, Optional<T>जिसमें शून्य-या-एक लंबाई में बदलने के लिए कुछ हद तक असुविधाजनक है Stream<T>। आप ऐसा कर सकते हैं:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
          .findFirst();

अंदर टर्नरी ऑपरेटर होना flatMapथोड़ा बोझिल है, हालांकि, ऐसा करने के लिए थोड़ा सहायक फ़ंक्शन लिखना बेहतर हो सकता है:

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon
 * whether a value is present.
 */
static <T> Stream<T> streamopt(Optional<T> opt) {
    if (opt.isPresent())
        return Stream.of(opt.get());
    else
        return Stream.empty();
}

Optional<Other> result =
    things.stream()
          .flatMap(t -> streamopt(resolve(t)))
          .findFirst();

यहां, मैंने resolve()एक अलग map()ऑपरेशन करने के बजाय कॉल को इनलाइन किया है , लेकिन यह स्वाद का मामला है।


2
मुझे नहीं लगता कि जावा अब 9 तक एपीआई बदल सकता है।
अकाल

5
@ हाईरफ थैंक्स। .Filter ()। मैप () तकनीक बहुत खराब नहीं है और सहायक विधियों पर निर्भरता से बचा जाता है। 'यदि कोई अधिक संक्षिप्त तरीका हो तो ट्वीड अच्छा होगा। मैं जांच कर रहा हूँ Optional.stream () जोड़ा गया।
स्टुअर्ट मार्क्स

43
मैं पसंद करता हूं:static <T> Stream<T> streamopt(Optional<T> opt) { return opt.map(Stream::of).orElse(Stream.empty()); }
kubek2k

5
काश वे बस एक Optionalअधिभार जोड़ते Stream#flatMap... इस तरह से आप बस लिख सकते हैंstream().flatMap(this::resolve)
फ्लेक्स

4
@flkes हाँ, हमने इस विचार के चारों ओर लात मारी है, लेकिन यह अब उस (JDK 9 में) सभी मूल्य को जोड़ने के लिए प्रतीत नहीं होता है Optional.stream()
स्टुअर्ट मार्क्स

69

मैं अपने दूसरे उत्तर के लिए उपयोगकर्ता srborlongan द्वारा प्रस्तावित संपादन के आधार पर यह दूसरा उत्तर जोड़ रहा हूं । मुझे लगता है कि प्रस्तावित तकनीक दिलचस्प थी, लेकिन यह वास्तव में मेरे जवाब को संपादित करने के रूप में उपयुक्त नहीं था। अन्य सहमत हुए और प्रस्तावित संपादन को वोट दिया गया। (मैं मतदाताओं में से एक नहीं था।) तकनीक में योग्यता है, हालांकि। यह सबसे अच्छा होता अगर srborlongan ने अपना उत्तर स्वयं पोस्ट किया होता। यह अभी तक नहीं हुआ है, और मैं नहीं चाहता था कि स्टैकऑवरफ्लो के मिस्ट्स में तकनीक खो जाए, इतिहास को संपादित करें, इसलिए मैंने इसे एक अलग उत्तर के रूप में खुद को बनाने का फैसला किया।

मूल रूप से तकनीक Optionalएक चतुर तरीके से कुछ तरीकों का उपयोग करने से बचने के लिए एक टर्नरी ऑपरेटर ( ? :) या यदि या किसी अन्य कथन का उपयोग करने के लिए है ।

मेरा इनलाइन उदाहरण इस तरह से फिर से लिखा जाएगा:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))
          .findFirst();

एक सहायक विधि का उपयोग करने वाला मेरा उदाहरण इस तरह से फिर से लिखा जाएगा:

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon
 * whether a value is present.
 */
static <T> Stream<T> streamopt(Optional<T> opt) {
    return opt.map(Stream::of)
              .orElseGet(Stream::empty);
}

Optional<Other> result =
    things.stream()
          .flatMap(t -> streamopt(resolve(t)))
          .findFirst();

टीका

आइए सीधे मूल बनाम संशोधित संस्करणों की तुलना करें:

// original
.flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())

// modified
.flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty))

मूल सीधा है अगर काम करने वाला दृष्टिकोण: हमें एक Optional<Other>; यदि इसका कोई मान है, तो हम उस मान से युक्त स्ट्रीम लौटाते हैं, और यदि इसका कोई मूल्य नहीं है, तो हम एक खाली स्ट्रीम लौटाते हैं। बहुत सरल और समझाने में आसान।

संशोधन चतुर है और इसका लाभ यह है कि यह सशर्त से बचा जाता है। (मुझे पता है कि कुछ लोग टर्नरी ऑपरेटर को नापसंद करते हैं। यदि इसका दुरुपयोग किया जाता है तो यह वास्तव में कोड को समझना मुश्किल बना सकता है।) हालांकि, कभी-कभी चीजें बहुत चालाक हो सकती हैं। संशोधित कोड भी एक के साथ शुरू होता है Optional<Other>। फिर यह कॉल Optional.mapकरता है जिसे निम्नानुसार परिभाषित किया गया है:

यदि कोई मान मौजूद है, तो उसे प्रदान की गई मैपिंग फ़ंक्शन लागू करें, और यदि परिणाम गैर-शून्य है, तो परिणाम का वर्णन करते हुए एक वैकल्पिक लौटाएं। अन्यथा एक खाली वैकल्पिक लौटें।

map(Stream::of)कॉल एक रिटर्न Optional<Stream<Other>>। यदि कोई मूल्य इनपुट वैकल्पिक में मौजूद था, तो लौटे वैकल्पिक में एक स्ट्रीम होता है जिसमें एकल अन्य परिणाम होता है। लेकिन यदि मान मौजूद नहीं था, तो परिणाम एक खाली वैकल्पिक है।

इसके बाद, कॉल orElseGet(Stream::empty)प्रकार का मान लौटाता है Stream<Other>। यदि इसका इनपुट मान मौजूद है, तो उसे वह मान मिलता है, जो एकल-तत्व है Stream<Other>। अन्यथा (यदि इनपुट मान अनुपस्थित है) तो यह खाली हो जाता है Stream<Other>। तो परिणाम सही है, मूल सशर्त कोड के समान है।

मेरे जवाब पर चर्चा कर रहे टिप्पणियों में, अस्वीकार किए गए संपादन के संबंध में, मैंने इस तकनीक को "अधिक संक्षिप्त लेकिन साथ ही अधिक अस्पष्ट" बताया था। मैं इसी से खड़ा हूं। मुझे यह पता लगाने में थोड़ा समय लगा कि यह क्या कर रहा था, और मुझे यह बताने में भी थोड़ा समय लगा कि यह क्या कर रहा है। कुंजी सूक्ष्मता से परिवर्तन Optional<Other>है Optional<Stream<Other>>। एक बार जब आप इसे दबा लेते हैं तो यह समझ में आता है, लेकिन यह मेरे लिए स्पष्ट नहीं था।

मैं स्वीकार करता हूँ, हालांकि, यह है कि शुरू में अस्पष्ट हैं चीजें समय के साथ मुहावरेदार हो सकती हैं। यह हो सकता है कि यह तकनीक व्यवहार में सबसे अच्छा तरीका है, कम से कम जब तक Optional.streamजोड़ा नहीं जाता है (यदि यह कभी भी हो)।

अद्यतन: Optional.stream JDK 9 में जोड़ा गया है।


16

आप इसे और अधिक संक्षिप्त नहीं कर सकते हैं जैसा कि आप पहले से ही कर रहे हैं।

आप दावा करते हैं कि आप नहीं चाहते हैं .filter(Optional::isPresent) और .map(Optional::get)

यह विधि @StuartMarks द्वारा हल किया गया है, हालाँकि परिणामस्वरूप अब आप इसे मैप करते हैं Optional<T>, इसलिए अब आपको उपयोग करने की आवश्यकता है .flatMap(this::streamopt)और get()अंत में।

तो यह अभी भी दो बयानों से बना है और आप अब नई विधि के साथ अपवाद प्राप्त कर सकते हैं! क्योंकि, अगर हर वैकल्पिक खाली है तो क्या होगा? फिर findFirst()एक खाली वैकल्पिक वापस आ जाएगा और आपका get()विफल हो जाएगा!

तो आपके पास क्या है:

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

है वास्तव में सबसे अच्छा तरीका है पूरा करने के लिए आप क्या चाहते हैं, और है कि आप एक के रूप में परिणाम सहेजना चाहते है Tएक के रूप में नहीं, Optional<T>

मैंने एक CustomOptional<T>वर्ग बनाने की स्वतंत्रता ली जो लपेटता है Optional<T>और एक अतिरिक्त विधि प्रदान करता है flatStream(),। ध्यान दें कि आप विस्तार नहीं कर सकते हैं Optional<T>:

class CustomOptional<T> {
    private final Optional<T> optional;

    private CustomOptional() {
        this.optional = Optional.empty();
    }

    private CustomOptional(final T value) {
        this.optional = Optional.of(value);
    }

    private CustomOptional(final Optional<T> optional) {
        this.optional = optional;
    }

    public Optional<T> getOptional() {
        return optional;
    }

    public static <T> CustomOptional<T> empty() {
        return new CustomOptional<>();
    }

    public static <T> CustomOptional<T> of(final T value) {
        return new CustomOptional<>(value);
    }

    public static <T> CustomOptional<T> ofNullable(final T value) {
        return (value == null) ? empty() : of(value);
    }

    public T get() {
        return optional.get();
    }

    public boolean isPresent() {
        return optional.isPresent();
    }

    public void ifPresent(final Consumer<? super T> consumer) {
        optional.ifPresent(consumer);
    }

    public CustomOptional<T> filter(final Predicate<? super T> predicate) {
        return new CustomOptional<>(optional.filter(predicate));
    }

    public <U> CustomOptional<U> map(final Function<? super T, ? extends U> mapper) {
        return new CustomOptional<>(optional.map(mapper));
    }

    public <U> CustomOptional<U> flatMap(final Function<? super T, ? extends CustomOptional<U>> mapper) {
        return new CustomOptional<>(optional.flatMap(mapper.andThen(cu -> cu.getOptional())));
    }

    public T orElse(final T other) {
        return optional.orElse(other);
    }

    public T orElseGet(final Supplier<? extends T> other) {
        return optional.orElseGet(other);
    }

    public <X extends Throwable> T orElseThrow(final Supplier<? extends X> exceptionSuppier) throws X {
        return optional.orElseThrow(exceptionSuppier);
    }

    public Stream<T> flatStream() {
        if (!optional.isPresent()) {
            return Stream.empty();
        }
        return Stream.of(get());
    }

    public T getTOrNull() {
        if (!optional.isPresent()) {
            return null;
        }
        return get();
    }

    @Override
    public boolean equals(final Object obj) {
        return optional.equals(obj);
    }

    @Override
    public int hashCode() {
        return optional.hashCode();
    }

    @Override
    public String toString() {
        return optional.toString();
    }
}

आप देखेंगे कि मैंने flatStream()यहाँ जोड़ा :

public Stream<T> flatStream() {
    if (!optional.isPresent()) {
        return Stream.empty();
    }
    return Stream.of(get());
}

इसके समान इस्तेमाल किया:

String result = Stream.of("a", "b", "c", "de", "fg", "hij")
        .map(this::resolve)
        .flatMap(CustomOptional::flatStream)
        .findFirst()
        .get();

आपको अभी भीStream<T> यहां लौटने की आवश्यकता होगी , क्योंकि आप वापस नहीं आ सकते T, क्योंकि यदि !optional.isPresent(), तो T == nullयदि आप इसे इस तरह की घोषणा करते हैं, लेकिन तब आपका .flatMap(CustomOptional::flatStream)प्रयास nullएक धारा में जोड़ने का होगा और यह संभव नहीं है।

उदाहरण के रूप में:

public T getTOrNull() {
    if (!optional.isPresent()) {
        return null;
    }
    return get();
}

इसके समान इस्तेमाल किया:

String result = Stream.of("a", "b", "c", "de", "fg", "hij")
        .map(this::resolve)
        .map(CustomOptional::getTOrNull)
        .findFirst()
        .get();

अब NullPointerExceptionधारा संचालन के अंदर फेंक देंगे ।

निष्कर्ष

आपके द्वारा उपयोग की जाने वाली विधि, वास्तव में सबसे अच्छी विधि है।


6

एक छोटा सा संस्करण का उपयोग reduce:

things.stream()
  .map(this::resolve)
  .reduce(Optional.empty(), (a, b) -> a.isPresent() ? a : b );

आप कम फ़ंक्शन को स्थिर उपयोगिता विधि में भी स्थानांतरित कर सकते हैं और फिर यह बन जाता है:

  .reduce(Optional.empty(), Util::firstPresent );

6
मुझे यह पसंद है, लेकिन यह इंगित करने के लायक है कि यह स्ट्रीम में प्रत्येक आइटम का मूल्यांकन करेगा, जबकि findFirst () केवल तब तक मूल्यांकन करेगा जब तक कि यह एक वर्तमान आइटम नहीं मिल जाता।
डंकन मैकग्रेगर

1
और दुर्भाग्य से, प्रत्येक संकल्प को निष्पादित करना एक सौदा-ब्रेकर है। लेकिन यह चतुर है।
योना एप्लेट्री

5

जैसा कि मेरा पिछला जवाब बहुत लोकप्रिय नहीं हुआ, मैं इसे एक और रास्ता दूंगा।

एक छोटा जवाब:

आप ज्यादातर सही रास्ते पर हैं। आपके इच्छित आउटपुट पर आने वाला सबसे छोटा कोड यह है

things.stream()
      .map(this::resolve)
      .filter(Optional::isPresent)
      .findFirst()
      .flatMap( Function.identity() );

यह आपकी सभी आवश्यकताओं को पूरा करेगा:

  1. इसे पहली प्रतिक्रिया मिलेगी जो एक गैर-रिक्त स्थान के लिए हल होती है Optional<Result>
  2. आवश्यकतानुसार इसे this::resolveआलसी कहते हैं
  3. this::resolve पहले गैर-रिक्त परिणाम के बाद नहीं बुलाया जाएगा
  4. यह वापस आ जाएगी Optional<Result>

लंबा जवाब

ओपी प्रारंभिक संस्करण की तुलना में एकमात्र संशोधन यह था कि मैंने .map(Optional::get)कॉल करने से पहले हटा दिया .findFirst()और .flatMap(o -> o)श्रृंखला में अंतिम कॉल के रूप में जोड़ा ।

जब भी स्ट्रीम को वास्तविक परिणाम मिलता है, तो डबल-ऑप्शनल से छुटकारा पाने का यह एक अच्छा प्रभाव है।

आप वास्तव में जावा में इससे कम नहीं जा सकते।

अधिक पारंपरिक forलूप तकनीक का उपयोग करके कोड का वैकल्पिक स्निपेट कोड की समान पंक्तियों की संख्या के बारे में होने वाला है और कमोबेश एक ही क्रम और आपके द्वारा किए जाने वाले संचालन की संख्या है:

  1. कॉलिंग this.resolve,
  2. के आधार पर फ़िल्टरिंग Optional.isPresent
  3. परिणाम और
  4. नकारात्मक परिणाम से निपटने का कोई तरीका (जब कुछ नहीं मिला)

बस यह साबित करने के लिए कि मेरा समाधान विज्ञापन के रूप में काम करता है, मैंने एक छोटा परीक्षण कार्यक्रम लिखा:

public class StackOverflow {

    public static void main( String... args ) {
        try {
            final int integer = Stream.of( args )
                    .peek( s -> System.out.println( "Looking at " + s ) )
                    .map( StackOverflow::resolve )
                    .filter( Optional::isPresent )
                    .findFirst()
                    .flatMap( o -> o )
                    .orElseThrow( NoSuchElementException::new )
                    .intValue();

            System.out.println( "First integer found is " + integer );
        }
        catch ( NoSuchElementException e ) {
            System.out.println( "No integers provided!" );
        }
    }

    private static Optional<Integer> resolve( String string ) {
        try {
            return Optional.of( Integer.valueOf( string ) );
        }
        catch ( NumberFormatException e )
        {
            System.out.println( '"' + string + '"' + " is not an integer");
            return Optional.empty();
        }
    }

}

(इसमें डिबगिंग और सत्यापित करने के लिए कुछ अतिरिक्त लाइनें हैं, जो केवल आवश्यकतानुसार कॉल करने के लिए ...)

कमांड लाइन पर इसे निष्पादित करने पर, मुझे निम्नलिखित परिणाम मिले:

$ java StackOferflow a b 3 c 4
Looking at a
"a" is not an integer
Looking at b
"b" is not an integer
Looking at 3
First integer found is 3

मुझे रोलाण्ड टीपीपी के समान लगता है। क्यों होता है किसी मेकअप धारा <धारा <>> और फ्लैट जब आप कर सकते हैं सिर्फ एक वैकल्पिक <वैकल्पिक <>> के साथ फ्लैट?
युवा ह्यून यू

3

अगर आपको थर्ड पार्टी लाइब्रेरी का उपयोग करने में कोई आपत्ति नहीं है तो आप Javaslang का उपयोग कर सकते हैं । यह स्काला जैसा है, लेकिन जावा में लागू किया गया है।

यह एक पूर्ण अपरिवर्तनीय संग्रह पुस्तकालय के साथ आता है, जो कि स्काला के समान है। ये संग्रह जावा के संग्रह और जावा 8 की स्ट्रीम को प्रतिस्थापित करते हैं। इसका विकल्प का अपना कार्यान्वयन भी है।

import javaslang.collection.Stream;
import javaslang.control.Option;

Stream<Option<String>> options = Stream.of(Option.some("foo"), Option.none(), Option.some("bar"));

// = Stream("foo", "bar")
Stream<String> strings = options.flatMap(o -> o);

यहाँ प्रारंभिक प्रश्न के उदाहरण के लिए एक समाधान है:

import javaslang.collection.Stream;
import javaslang.control.Option;

public class Test {

    void run() {

        // = Stream(Thing(1), Thing(2), Thing(3))
        Stream<Thing> things = Stream.of(new Thing(1), new Thing(2), new Thing(3));

        // = Some(Other(2))
        Option<Other> others = things.flatMap(this::resolve).headOption();
    }

    Option<Other> resolve(Thing thing) {
        Other other = (thing.i % 2 == 0) ? new Other(i + "") : null;
        return Option.of(other);
    }

}

class Thing {
    final int i;
    Thing(int i) { this.i = i; }
    public String toString() { return "Thing(" + i + ")"; }
}

class Other {
    final String s;
    Other(String s) { this.s = s; }
    public String toString() { return "Other(" + s + ")"; }
}

डिस्क्लेमर: मैं जावलासंग का निर्माता हूं।


3

पार्टी के लिए देर हो रही है, लेकिन क्या

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .findFirst().get();

यदि आप मैन्युअल रूप से स्ट्रीम करने के लिए वैकल्पिक परिवर्तित करने के लिए उपयोग विधि बनाते हैं, तो आप अंतिम प्राप्त () से छुटकारा पा सकते हैं:

things.stream()
    .map(this::resolve)
    .flatMap(Util::optionalToStream)
    .findFirst();

यदि आप अपने रिज़ॉल्यूशन फ़ंक्शन से तुरंत स्ट्रीम वापस आते हैं, तो आप एक और लाइन बचाते हैं।


3

मैं कार्यात्मक एपीआई के लिए हेल्पर्स बनाने के लिए कारखाने के तरीकों को बढ़ावा देना चाहता हूं :

Optional<R> result = things.stream()
        .flatMap(streamopt(this::resolve))
        .findFirst();

कारखाने विधि:

<T, R> Function<T, Stream<R>> streamopt(Function<T, Optional<R>> f) {
    return f.andThen(Optional::stream); // or the J8 alternative:
    // return t -> f.apply(t).map(Stream::of).orElseGet(Stream::empty);
}

तर्क:

  • सामान्य तौर पर विधि संदर्भों के साथ, लैम्ब्डा अभिव्यक्तियों की तुलना में, आप आकस्मिक दायरे से किसी वैरिएबल पर कब्जा नहीं कर सकते, जैसे:

    t -> streamopt(resolve(o))

  • यह रचना योग्य है, आप उदाहरण के Function::andThenलिए फ़ैक्टरी विधि पर कॉल कर सकते हैं :

    streamopt(this::resolve).andThen(...)

    जबकि एक लंबोदर के मामले में, आपको इसे पहले डालना होगा:

    ((Function<T, Stream<R>>) t -> streamopt(resolve(t))).andThen(...)


3

नल द्वारा समर्थित है मेरा पुस्तकालय AbacusUtil प्रदान की । यहाँ कोड है:

Stream.of(things).map(e -> resolve(e).orNull()).skipNull().first();

3

यदि आप जावा 8 के साथ फंस गए हैं लेकिन आपके पास अमरूद 21.0 या नए तक पहुंच है, तो आप उपयोग कर सकते हैं Streams.stream वैकल्पिक को एक स्ट्रीम में बदलने के लिए ।

इस प्रकार, दिया गया

import com.google.common.collect.Streams;

तुम लिख सकते हो

Optional<Other> result =
    things.stream()
        .map(this::resolve)
        .flatMap(Streams::stream)
        .findFirst();

0

उस बारे में क्या?

private static List<String> extractString(List<Optional<String>> list) {
    List<String> result = new ArrayList<>();
    list.forEach(element -> element.ifPresent(result::add));
    return result;
}

https://stackoverflow.com/a/58281000/3477539


जब आप स्ट्रीम और संग्रह कर सकते हैं तो ऐसा क्यों करें?
OneCricketeer

return list.stream().filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList())), बस सवाल की तरह (और आपके जुड़े जवाब) है ...
OneCricketeer

मैं गलत हो सकता हूं, लेकिन मैं isPresent () का उपयोग करने पर विचार करता हूं और फिर प्राप्त करना () एक अच्छा अभ्यास नहीं है। इसलिए मैं उससे दूर होने की कोशिश करता हूं।
रस्तमन

यदि आप .get() बिना उपयोग करते हैं isPresent(), तो आपको IntelliJ में चेतावनी मिलती है
OneCricketeer

-5

सबसे अधिक संभावना है कि आप इसे गलत कर रहे हैं।

जावा 8 वैकल्पिक का उपयोग इस तरह से करने के लिए नहीं है। यह आम तौर पर केवल टर्मिनल स्ट्रीम ऑपरेशन के लिए आरक्षित होता है, जो मान वापस नहीं कर सकता है, जैसे कि उदाहरण के लिए खोजें।

आपके मामले में पहले उन वस्तुओं को फ़िल्टर करने का एक सस्ता तरीका खोजने का प्रयास करना बेहतर हो सकता है जो फिर से उपयोग करने योग्य हैं और फिर पहले आइटम को वैकल्पिक के रूप में प्राप्त करते हैं और इसे अंतिम ऑपरेशन के रूप में हल करते हैं। बेहतर अभी तक - फ़िल्टर करने के बजाय, पहले resolvable आइटम ढूंढें और इसे हल करें।

things.filter(Thing::isResolvable)
      .findFirst()
      .flatMap(this::resolve)
      .get();

अंगूठे का नियम यह है कि आप धारा में वस्तुओं की संख्या को कम करने का प्रयास करें इससे पहले कि आप उन्हें किसी और चीज में बदल दें। YMMV बेशक।


6
मुझे लगता है कि ओपी का संकल्प () विधि वैकल्पिक लौटना <अन्य> वैकल्पिक का पूरी तरह से समझदार उपयोग है। मैं निश्चित रूप से ओपी के समस्या डोमेन से बात नहीं कर सकता, लेकिन यह हो सकता है कि यह निर्धारित करने का तरीका कि क्या कुछ हल करने योग्य है, इसे हल करने का प्रयास करना है। यदि ऐसा है, तो वैकल्पिक एक एकल एपीआई कॉल में संकल्प के परिणाम के साथ, "यह इस योग्य था" के बूलियन परिणाम को फ्यूज करता है।
स्टुअर्ट मार्क्स

2
स्टुअर्ट मूल रूप से सही है। मेरे पास वांछनीयता के क्रम में खोज शब्दों का एक सेट है, और मैं पहले वाले परिणाम का पता लगाने के लिए देख रहा हूं जो कुछ भी देता है। तो मूल रूप से Optional<Result> searchFor(Term t)। ऐसा लगता है कि वैकल्पिक का इरादा फिट है। इसके अलावा, स्ट्रीम () का आलसी मूल्यांकन किया जाना चाहिए, इसलिए पहले मिलान वाले अतीत के शब्दों को हल करने वाले कोई अतिरिक्त कार्य नहीं होने चाहिए।
योना एपेलेट्री

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