जावा स्ट्रीम को 1 और केवल 1 तत्व को फ़िल्टर करें


229

मैं Streamतत्वों को खोजने के लिए जावा 8 एस का उपयोग करने की कोशिश कर रहा हूं LinkedList। हालांकि, मैं गारंटी देना चाहता हूं कि फिल्टर मानदंडों में एक और एक ही मैच है।

यह कोड लें:

public static void main(String[] args) {

    LinkedList<User> users = new LinkedList<>();
    users.add(new User(1, "User1"));
    users.add(new User(2, "User2"));
    users.add(new User(3, "User3"));

    User match = users.stream().filter((user) -> user.getId() == 1).findAny().get();
    System.out.println(match.toString());
}

static class User {

    @Override
    public String toString() {
        return id + " - " + username;
    }

    int id;
    String username;

    public User() {
    }

    public User(int id, String username) {
        this.id = id;
        this.username = username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public int getId() {
        return id;
    }
}

यह कोड Userउनकी आईडी के आधार पर मिलता है । लेकिन Userफ़िल्टर कितने से मेल खाते हैं इसकी कोई गारंटी नहीं है ।

फ़िल्टर लाइन को इसमें बदलना:

User match = users.stream().filter((user) -> user.getId() < 0).findAny().get();

फेंक देंगे एक NoSuchElementException(अच्छा!)

मैं यह चाहूंगा कि यदि एक से अधिक मैच हों, तो त्रुटि को फेंक दें। क्या इसे करने का कोई तरीका है?


count()एक टर्मिनल ऑपरेशन है, इसलिए आप ऐसा नहीं कर सकते। इसके बाद स्ट्रीम का उपयोग नहीं किया जा सकता है।
एलेक्सिस सी।

ठीक है, धन्यवाद @ZouZou। मैं पूरी तरह से निश्चित नहीं था कि उस विधि ने क्या किया। क्यों नहीं है Stream::size?
४४ पर पुनर्वसु

7
@ryvantage क्योंकि एक धारा का केवल एक बार उपयोग किया जा सकता है: इसके आकार की गणना करने का अर्थ है कि इसके ऊपर "पुनरावृत्ति" करना और उसके बाद आप किसी भी धारा का उपयोग नहीं कर सकते।
assylias

3
वाह। उस एक टिप्पणी ने मुझे यह समझने में मदद की कि Streamमैंने पहले जितना किया था ...
rantvantage

2
यह तब होता है जब आपको पता चलता है कि आपको एक का उपयोग करने की आवश्यकता थी LinkedHashSet(यह मानते हुए कि आप प्रविष्टि क्रम को संरक्षित रखना चाहते हैं) या एक HashSetसाथ। यदि आपका संग्रह केवल एकल उपयोगकर्ता आईडी खोजने के लिए उपयोग किया जाता है, तो आप अन्य सभी आइटम क्यों एकत्र कर रहे हैं? यदि कोई संभावना है कि आपको हमेशा कुछ उपयोगकर्ता आईडी खोजने की आवश्यकता होगी जो अद्वितीय होने की भी आवश्यकता है, तो एक सूची का उपयोग क्यों करें और एक सेट नहीं? आप पीछे की ओर प्रोग्रामिंग कर रहे हैं। नौकरी के लिए सही संग्रह का उपयोग करें और अपने आप को इस सिरदर्द से
बचाएं

जवाबों:


190

एक प्रथा बनाएँ Collector

public static <T> Collector<T, ?, T> toSingleton() {
    return Collectors.collectingAndThen(
            Collectors.toList(),
            list -> {
                if (list.size() != 1) {
                    throw new IllegalStateException();
                }
                return list.get(0);
            }
    );
}

हम का उपयोग Collectors.collectingAndThenहमारे वांछित निर्माण करने के लिए Collectorसे

  1. कलेक्टर के Listसाथ हमारी वस्तुओं को एकत्रित करना Collectors.toList()
  2. अंत में एक अतिरिक्त फिनिशर को लागू करना, जो एकल तत्व को लौटाता है - या IllegalStateExceptionयदि एक फेंकता है list.size != 1

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

User resultUser = users.stream()
        .filter(user -> user.getId() > 0)
        .collect(toSingleton());

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

एक विकल्प - यकीनन कम सुरुचिपूर्ण - समाधान:

आप एक 'वर्कअराउंड' का उपयोग कर सकते हैं जिसमें शामिल है peek()और एक है AtomicInteger, लेकिन वास्तव में आपको इसका उपयोग नहीं करना चाहिए।

आप जो कर सकते हैं, वह सिर्फ Listइस तरह से इकट्ठा करना है :

LinkedList<User> users = new LinkedList<>();
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));
List<User> resultUserList = users.stream()
        .filter(user -> user.getId() == 1)
        .collect(Collectors.toList());
if (resultUserList.size() != 1) {
    throw new IllegalStateException();
}
User resultUser = resultUserList.get(0);

23
अमरूद Iterables.getOnlyElementइन समाधानों को छोटा कर देगा और बेहतर त्रुटि संदेश प्रदान करेगा। बस साथी पाठकों के लिए एक टिप के रूप में जो पहले से ही Google अमरूद का उपयोग करते हैं।
टिम बुथ

2
मैंने इस विचार को एक वर्ग में लपेट दिया - gist.github.com/denov/a7eac36a3cda041f8afeabcef09d16fc
denov

1
@ लॉनलीनॉरन कृपया मेरे कोड को संपादित न करें। यह मुझे उस स्थिति में डालता है जहाँ मुझे अपने पूरे उत्तर को मान्य करने की आवश्यकता होती है, जिसे मैंने चार साल पहले लिखा है, और मेरे पास अभी इसके लिए समय नहीं है।
स्काइवी

2
@skiwi: लोनली का संपादन सहायक और सही था, इसलिए मैंने समीक्षा के बाद इसे फिर से शुरू किया। आज इस उत्तर पर जाने वाले लोग इस बात की परवाह नहीं करते हैं कि आप किस तरह से उत्तर में आए हैं, उन्हें पुराने संस्करण और नए संस्करण और अपडेटेड अनुभाग को देखने की आवश्यकता नहीं है । यह आपके उत्तर को अधिक भ्रमित और कम सहायक बनाता है। पोस्ट को अंतिम स्थिति में रखना बेहतर है , और यदि लोग यह देखना चाहते हैं कि यह सब कैसे खेला गया तो वे पोस्ट इतिहास को देख सकते हैं।
मार्टिन पीटर्स

1
@skiwi: जवाब में कोड है बिल्कुल कि तुम क्या लिखा है। सभी संपादक ने आपकी पोस्ट को साफ कर दिया था, केवल पोस्ट में बने हुए संस्करण द्वारा बताई गई परिभाषा के पुराने संस्करण को हटाकरsingletonCollector() , और इसका नाम बदलकर toSingleton()। मेरी जावा स्ट्रीम विशेषज्ञता थोड़ी कठोर है, लेकिन नाम बदलने से मुझे मदद मिलती है। इस परिवर्तन की समीक्षा करने में मुझे 2 मिनट, सबसे ऊपर लगे। यदि आपके पास संपादन की समीक्षा करने का समय नहीं है, तो क्या मैं सुझाव दे सकता हूं कि आप भविष्य में किसी और से ऐसा करने के लिए कहें, शायद जावा चैट रूम में ?
मार्टिन पीटर्स

118

पूर्णता के लिए, यहाँ 'वन-लाइनर' @ प्रुनज के उत्कृष्ट उत्तर के अनुरूप है:

User user1 = users.stream()
        .filter(user -> user.getId() == 1)
        .reduce((a, b) -> {
            throw new IllegalStateException("Multiple elements: " + a + ", " + b);
        })
        .get();

यह स्ट्रीम से एकमात्र मिलान तत्व प्राप्त करता है, फेंक देता है

  • NoSuchElementException यदि धारा खाली है, या
  • IllegalStateException यदि धारा में एक से अधिक मिलान तत्व हैं।

इस दृष्टिकोण की एक भिन्नता एक अपवाद को जल्दी से फेंकने से बचती है और इसके बजाय परिणाम को Optionalएकमात्र तत्व के रूप में दर्शाती है , या शून्य या एकाधिक तत्व होने पर (खाली) कुछ भी नहीं है:

Optional<User> user1 = users.stream()
        .filter(user -> user.getId() == 1)
        .collect(Collectors.reducing((a, b) -> null));

3
मुझे इस उत्तर में प्रारंभिक दृष्टिकोण पसंद है। अनुकूलन प्रयोजनों के लिए, यह संभव है पिछले कन्वर्ट करने के get()लिएorElseThrow()
arin

1
मैं इस एक की संक्षिप्तता को पसंद करता हूं, और यह तथ्य कि यह हर बार इसे कहा जाता है एक गैर-आवश्यक सूची उदाहरण बनाने से बचें।
लॉर्डऑफइंग्स

83

अन्य उत्तर जिसमें कस्टम लिखना शामिल है, Collectorसंभवतः अधिक कुशल हैं (जैसे कि लुई वास्समैन , +1), लेकिन अगर आप संक्षिप्तता चाहते हैं, तो मैं निम्नलिखित सुझाव दूंगा:

List<User> result = users.stream()
    .filter(user -> user.getId() == 1)
    .limit(2)
    .collect(Collectors.toList());

फिर परिणाम सूची के आकार को सत्यापित करें।

if (result.size() != 1) {
  throw new IllegalStateException("Expected exactly one user but got " + result);
User user = result.get(0);
}

5
का फ़ायदा क्या है limit(2)इस समाधान में? इससे क्या फर्क पड़ेगा कि परिणामी सूची 2 या 100 थी? यदि यह
१.१

18
दूसरा मैच देखने पर यह तुरंत बंद हो जाता है। यह वही है जो सभी फैंसी कलेक्टर करते हैं, बस अधिक कोड का उपयोग करते हुए। :-)
स्टुअर्ट मार्क्स

10
जोड़ने के बारे में कैसेCollectors.collectingAndThen(toList(), l -> { if (l.size() == 1) return l.get(0); throw new RuntimeException(); })
लुकास एडर

1
Javadoc सीमा के परम के बारे में यह कहता है maxSize: the number of elements the stream should be limited to:। तो, .limit(1)इसके बजाय नहीं होना चाहिए .limit(2)?
एलेक्सबेट

5
@alexbt समस्या कथन यह सुनिश्चित करने के लिए है कि वास्तव में एक (अधिक नहीं, कम नहीं) मिलान तत्व है। मेरे कोड के बाद, कोई result.size()यह सुनिश्चित करने के लिए परीक्षण कर सकता है कि यह 1 के बराबर है। यदि यह 2 है, तो एक से अधिक मैच हैं, इसलिए यह एक त्रुटि है। यदि कोड के बजाय limit(1), एक से अधिक मैच एक ही तत्व में परिणाम होगा, जो वहाँ से वास्तव में एक मैच जा रहा है प्रतिष्ठित नहीं किया जा सकता है। इससे ओपी के बारे में चिंतित एक त्रुटि मामला याद आ जाएगा।
स्टुअर्ट मार्क्स

67

अमरूद प्रदान करता है MoreCollectors.onlyElement()जो यहाँ सही काम करता है। लेकिन अगर आपको इसे स्वयं करना है, तो आप इसके Collectorलिए अपना खुद का रोल कर सकते हैं :

<E> Collector<E, ?, Optional<E>> getOnly() {
  return Collector.of(
    AtomicReference::new,
    (ref, e) -> {
      if (!ref.compareAndSet(null, e)) {
         throw new IllegalArgumentException("Multiple values");
      }
    },
    (ref1, ref2) -> {
      if (ref1.get() == null) {
        return ref2;
      } else if (ref2.get() != null) {
        throw new IllegalArgumentException("Multiple values");
      } else {
        return ref1;
      }
    },
    ref -> Optional.ofNullable(ref.get()),
    Collector.Characteristics.UNORDERED);
}

... या के Holderबजाय अपने खुद के प्रकार का उपयोग कर AtomicReference। आप Collectorजितना चाहें उतना पुन: उपयोग कर सकते हैं।


@ skiwi का सिंगलटन कोलोरेक्टर इससे छोटा और आसान था, इसलिए मैंने उसे चेक दिया। लेकिन उत्तर में सर्वसम्मति देखने के लिए अच्छा है: एक रिवाज Collectorजाने का रास्ता था।
२।

1
काफी उचित। मैं मुख्य रूप से गति के लिए लक्ष्य कर रहा था, न कि सहमति।
लुई वासरमैन

1
हाँ? तुम्हारा तेज क्यों है?
२०:४४ पर २y

3
अधिकतर इसलिए क्योंकि Listएक एकल परस्पर संदर्भ की तुलना में सभी को आवंटित करना अधिक महंगा है।
लुई वासरमैन

1
@LouisWasserman, के बारे में अंतिम अद्यतन वाक्य MoreCollectors.onlyElement()वास्तव में पहले होना चाहिए (और शायद केवल :))
Piotr Findeisen

46

अमरूद MoreCollectors.onlyElement()( जावाडॉक ) का उपयोग करें ।

यह वही करता है जो आप चाहते हैं और फेंकता है IllegalArgumentExceptionयदि स्ट्रीम में दो या अधिक तत्व होते हैं, और NoSuchElementExceptionयदि स्ट्रीम खाली है।

उपयोग:

import static com.google.common.collect.MoreCollectors.onlyElement;

User match =
    users.stream().filter((user) -> user.getId() < 0).collect(onlyElement());

2
अन्य उपयोगकर्ताओं के लिए नोट: MoreCollectorsअभी तक (2016-12) के रूप में रिलीज़ नहीं अप्रकाशित संस्करण 21 का हिस्सा है
qerub

2
यह जवाब ऊपरी तौर पर जाना चाहिए।
इमदादुल सवोन

31

"एस्केप हैच" ऑपरेशन आपको अजीब चीजें करने देता है जो अन्यथा धाराओं द्वारा समर्थित नहीं हैं Iterator:

Iterator<T> it = users.stream().filter((user) -> user.getId() < 0).iterator();
if (!it.hasNext()) 
    throw new NoSuchElementException();
else {
    result = it.next();
    if (it.hasNext())
        throw new TooManyElementsException();
}

अमरूद में एक Iteratorतत्व लेने की सुविधा है और एकमात्र तत्व प्राप्त करने के लिए, फेंकने पर यदि शून्य या कई तत्व हैं, जो नीचे n-1 लाइनों को बदल सकता है।


4
अमरूद की विधि: Iterators.getOnlyElement (Iterator <T> iterator)।
13

23

अपडेट करें

@ होलजर से टिप्पणी में अच्छा सुझाव:

Optional<User> match = users.stream()
              .filter((user) -> user.getId() > 1)
              .reduce((u, v) -> { throw new IllegalStateException("More than one ID found") });

मूल उत्तर

अपवाद द्वारा फेंक दिया जाता है Optional#get, लेकिन यदि आपके पास एक से अधिक तत्व हैं जो मदद नहीं करेंगे। आप उपयोगकर्ताओं को एक संग्रह में एकत्र कर सकते हैं जो केवल एक आइटम को स्वीकार करता है, उदाहरण के लिए:

User match = users.stream().filter((user) -> user.getId() > 1)
                  .collect(toCollection(() -> new ArrayBlockingQueue<User>(1)))
                  .poll();

जो एक फेंकता है java.lang.IllegalStateException: Queue full, लेकिन वह बहुत ज्यादा हैकई लगता है।

या आप एक वैकल्पिक के साथ संयुक्त कमी का उपयोग कर सकते हैं:

User match = Optional.ofNullable(users.stream().filter((user) -> user.getId() > 1)
                .reduce(null, (u, v) -> {
                    if (u != null && v != null)
                        throw new IllegalStateException("More than one ID found");
                    else return u == null ? v : u;
                })).get();

कमी अनिवार्य रूप से लौटती है:

  • कोई उपयोगकर्ता नहीं मिला है तो अशक्त
  • उपयोगकर्ता यदि केवल एक ही पाया जाता है
  • एक से अधिक पाए जाने पर एक अपवाद फेंकता है

परिणाम तब एक वैकल्पिक में लपेटा जाता है।

लेकिन सबसे सरल समाधान शायद एक संग्रह में इकट्ठा करना होगा, यह जांचें कि इसका आकार 1 है और एकमात्र तत्व प्राप्त करें।


1
मैं nullउपयोग करने से रोकने के लिए एक पहचान तत्व ( ) जोड़ूंगा get()। अफसोस की बात reduceयह है कि जैसा आप सोचते हैं कि यह काम नहीं कर रहा है, इस पर विचार करें Streamकि इसमें nullतत्व हैं, शायद आपको लगता है कि आपने इसे कवर किया था, लेकिन मैं हो सकता हूं [User#1, null, User#2, null, User#3], अब यह एक अपवाद नहीं होगा जो मुझे लगता है, जब तक कि मैं यहां गलत नहीं हूं।
स्किवि

2
@Skiwi यदि अशक्त तत्व हैं तो फ़िल्टर पहले NPE फेंक देगा।
assylias

2
चूँकि आप जानते हैं कि स्ट्रीम nullरिडक्शन फंक्शन को पास नहीं कर सकता है , पहचान मान तर्क को हटाकर फंक्शन में पूरी डील को nullअप्रचलित कर देगा: reduce( (u,v) -> { throw new IllegalStateException("More than one ID found"); } )काम करता है और इससे भी बेहतर, यह पहले से ही एक रिटर्न देता है Optional, कॉलिंग के लिए आवश्यकता को पूरा Optional.ofNullableकरता है। परिणाम।
होल्गर

15

एक विकल्प कमी का उपयोग करना है: (यह उदाहरण स्ट्रिंग्स का उपयोग करता है, लेकिन किसी भी ऑब्जेक्ट प्रकार सहित आसानी से लागू हो सकता है User)

List<String> list = ImmutableList.of("one", "two", "three", "four", "five", "two");
String match = list.stream().filter("two"::equals).reduce(thereCanBeOnlyOne()).get();
//throws NoSuchElementException if there are no matching elements - "zero"
//throws RuntimeException if duplicates are found - "two"
//otherwise returns the match - "one"
...

//Reduction operator that throws RuntimeException if there are duplicates
private static <T> BinaryOperator<T> thereCanBeOnlyOne()
{
    return (a, b) -> {throw new RuntimeException("Duplicate elements found: " + a + " and " + b);};
}

तो Userआपके साथ इस मामले के लिए :

User match = users.stream().filter((user) -> user.getId() < 0).reduce(thereCanBeOnlyOne()).get();

8

कम का उपयोग करना

यह मेरे द्वारा पाया गया सरल और लचीला तरीका है (जो @prunge उत्तर पर आधारित है)

Optional<User> user = users.stream()
        .filter(user -> user.getId() == 1)
        .reduce((a, b) -> {
            throw new IllegalStateException("Multiple elements: " + a + ", " + b);
        })

इस तरह आप प्राप्त करते हैं:

  • वैकल्पिक - हमेशा अपनी वस्तु के साथ या Optional.empty()यदि मौजूद नहीं है
  • यदि एक से अधिक तत्व हैं, तो अपवाद (अंततः आपके कस्टम प्रकार / संदेश के साथ)

6

मुझे लगता है कि यह तरीका अधिक सरल है:

User resultUser = users.stream()
    .filter(user -> user.getId() > 0)
    .findFirst().get();

4
यह केवल पहली बार मिला, लेकिन मामला अपवाद को फेंकने का भी था जब यह एक से अधिक है
lczapski

5

का उपयोग करना Collector:

public static <T> Collector<T, ?, Optional<T>> toSingleton() {
    return Collectors.collectingAndThen(
            Collectors.toList(),
            list -> list.size() == 1 ? Optional.of(list.get(0)) : Optional.empty()
    );
}

उपयोग:

Optional<User> result = users.stream()
        .filter((user) -> user.getId() < 0)
        .collect(toSingleton());

हम एक वापसी करते हैं Optional, क्योंकि हम आमतौर पर Collectionएक तत्व को शामिल करने के लिए मान नहीं सकते हैं । यदि आप पहले से ही जानते हैं कि यह मामला है, तो कॉल करें:

User user = result.orElseThrow();

यह कॉलर पर त्रुटि को हैंडल करने का बोझ डालता है - जैसा कि यह होना चाहिए।



1

हम RxJava (बहुत शक्तिशाली प्रतिक्रियाशील विस्तार पुस्तकालय) का उपयोग कर सकते हैं

LinkedList<User> users = new LinkedList<>();
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));

User userFound =  Observable.from(users)
                  .filter((user) -> user.getId() == 1)
                  .single().toBlocking().first();

एकल ऑपरेटर एक अपवाद फेंकता है तो कोई उपयोगकर्ता या एक से अधिक उपयोगकर्ता पाया जाता है।


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

1

के रूप में Collectors.toMap(keyMapper, valueMapper)एक ही कुंजी के साथ कई प्रविष्टियों को संभालने के लिए एक फेंकने वाले विलय का उपयोग करना आसान है:

List<User> users = new LinkedList<>();
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));

int id = 1;
User match = Optional.ofNullable(users.stream()
  .filter(user -> user.getId() == id)
  .collect(Collectors.toMap(User::getId, Function.identity()))
  .get(id)).get();

आपको IllegalStateExceptionडुप्लीकेट चाबियां मिलेंगी । लेकिन अंत में मुझे यकीन नहीं है कि अगर कोड का उपयोग करके अधिक पठनीय नहीं होगा if


1
ठीक समाधान! और यदि आप करते हैं .collect(Collectors.toMap(user -> "", Function.identity())).get(""), तो आपके पास एक अधिक सामान्य व्यवहार है।
ग्लोगल

1

मैं उन दो संग्राहकों का उपयोग कर रहा हूं:

public static <T> Collector<T, ?, Optional<T>> zeroOrOne() {
    return Collectors.reducing((a, b) -> {
        throw new IllegalStateException("More than one value was returned");
    });
}

public static <T> Collector<T, ?, T> onlyOne() {
    return Collectors.collectingAndThen(zeroOrOne(), Optional::get);
}

साफ! 0 तत्वों के लिए> 1 तत्वों, और NoSuchElementException` (में ) के लिए onlyOne()फेंकता है । IllegalStateExceptionOptional::get
सिमोन 04

@ simon04 आप इन तरीकों का अधिक भार उठा सकते Supplierहैं (Runtime)Exception
जेवियर दुरि

1

यदि आप एक 3 पार्टी पुस्तकालय का उपयोग कर, कोई आपत्ति नहीं है SequenceMसे साइक्लोप धाराओं (और LazyFutureStreamसे सरल प्रतिक्रिया ) दोनों एक एकल और singleOptional ऑपरेटरों की है।

singleOptional()यदि कोई तत्व हैं 0या एक से अधिक 1तत्व हैं तो अपवाद छोड़ Streamदेता है, अन्यथा यह एकल मान लौटाता है।

String result = SequenceM.of("x")
                          .single();

SequenceM.of().single(); // NoSuchElementException

SequenceM.of(1, 2, 3).single(); // NoSuchElementException

String result = LazyFutureStream.fromStream(Stream.of("x"))
                          .single();

singleOptional()रिटर्न Optional.empty()अगर कोई मान या में एक से अधिक मान रहे हैं Stream

Optional<String> result = SequenceM.fromStream(Stream.of("x"))
                          .singleOptional(); 
//Optional["x"]

Optional<String> result = SequenceM.of().singleOptional(); 
// Optional.empty

Optional<String> result =  SequenceM.of(1, 2, 3).singleOptional(); 
// Optional.empty

प्रकटीकरण - मैं दोनों पुस्तकालयों का लेखक हूं।


0

मैं प्रत्यक्ष-दृष्टिकोण के साथ गया और बस बात को लागू किया:

public class CollectSingle<T> implements Collector<T, T, T>, BiConsumer<T, T>, Function<T, T>, Supplier<T> {
T value;

@Override
public Supplier<T> supplier() {
    return this;
}

@Override
public BiConsumer<T, T> accumulator() {
    return this;
}

@Override
public BinaryOperator<T> combiner() {
    return null;
}

@Override
public Function<T, T> finisher() {
    return this;
}

@Override
public Set<Characteristics> characteristics() {
    return Collections.emptySet();
}

@Override //accumulator
public void accept(T ignore, T nvalue) {
    if (value != null) {
        throw new UnsupportedOperationException("Collect single only supports single element, "
                + value + " and " + nvalue + " found.");
    }
    value = nvalue;
}

@Override //supplier
public T get() {
    value = null; //reset for reuse
    return value;
}

@Override //finisher
public T apply(T t) {
    return value;
}


} 

JUnit परीक्षण के साथ:

public class CollectSingleTest {

@Test
public void collectOne( ) {
    List<Integer> lst = new ArrayList<>();
    lst.add(7);
    Integer o = lst.stream().collect( new CollectSingle<>());
    System.out.println(o);
}

@Test(expected = UnsupportedOperationException.class)
public void failOnTwo( ) {
    List<Integer> lst = new ArrayList<>();
    lst.add(7);
    lst.add(8);
    Integer o = lst.stream().collect( new CollectSingle<>());
}

}

यह कार्यान्वयन थ्रेडसेफ़ नहीं है


0
User match = users.stream().filter((user) -> user.getId()== 1).findAny().orElseThrow(()-> new IllegalArgumentException());

5
हालांकि यह कोड प्रश्न को हल कर सकता है, जिसमें यह भी बताया गया है कि यह समस्या कैसे और क्यों हल करती है, इससे वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद मिलेगी, और संभवतः अधिक वोटों का परिणाम होगा। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है। स्पष्टीकरण जोड़ने के लिए कृपया अपना उत्तर संपादित करें और संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
डेविड बक

-2

क्या आपने यह कोशिश की है

long c = users.stream().filter((user) -> user.getId() == 1).count();
if(c > 1){
    throw new IllegalStateException();
}

long count()
Returns the count of elements in this stream. This is a special case of a reduction and is equivalent to:

     return mapToLong(e -> 1L).sum();

This is a terminal operation.

स्रोत: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Sthis.html


3
यह कहा गया था कि यह count()उपयोग करने के लिए अच्छा नहीं है क्योंकि यह एक टर्मिनल ऑपरेशन है।
27

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