ফিল্টার করুন জাভা স্ট্রিম 1 এবং কেবল 1 টি উপাদান


228

আমি জাভা 8 Streamগুলি একটিতে উপাদানগুলি খুঁজতে ব্যবহার করার চেষ্টা করছি 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 কারণ একটি স্ট্রিম কেবল একবার ব্যবহার করা যেতে পারে: এর আকার গণনা করার অর্থ এটির উপর "পুনরাবৃত্তি" এবং এর পরে আপনি আর স্ট্রিমটি আর ব্যবহার করতে পারবেন না।
অ্যাসিলিয়াস

3
কি দারুন. এই মন্তব্যটি আমাকে Streamআগের চেয়ে অনেক বেশি বুঝতে সাহায্য করেছে ...
রাওয়ান্টেজ

2
এটি যখন আপনি বুঝতে পারেন যে আপনার কোনও LinkedHashSet(সন্নিবেশকরণের আদেশটি সংরক্ষণ করা চাইছেন) ধরে নেওয়া বা একটি HashSetপাশাপাশি ব্যবহার করার দরকার পড়েছিল । যদি আপনার সংগ্রহটি কেবলমাত্র একটি একক ব্যবহারকারী আইডি সন্ধান করতে ব্যবহৃত হয়, তবে আপনি কেন অন্য সমস্ত আইটেম সংগ্রহ করছেন? যদি এমন কোনও সম্ভাবনা থাকে যা আপনার সর্বদা কিছু ইউজার আইডি খুঁজে বের করতে হবে যা অনন্য হওয়াও প্রয়োজন, তবে কেন একটি তালিকা ব্যবহার করে একটি সেট নয়? আপনি পিছনে প্রোগ্রামিং হয়। কাজের জন্য সঠিক সংগ্রহটি ব্যবহার করুন এবং নিজেকে এই মাথাব্যাথা বাঁচান
smac89

উত্তর:


189

একটি কাস্টম তৈরি করুন 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এটিকে আপনার পছন্দমতো কাস্টমাইজ করতে পারেন, উদাহরণস্বরূপ কনস্ট্রাক্টারে আর্গুমেন্ট হিসাবে ব্যতিক্রমটি দিন, দুটি মানকে আরও কিছু করার অনুমতি দেওয়ার জন্য এটি টুইট করুন।

একটি বিকল্প - যুক্তিসঙ্গত কম মার্জিত - সমাধান:

আপনি একটি 'workaround' ব্যবহার করতে পারেন যা জড়িত 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এই সমাধানগুলি সংক্ষিপ্ত করে এবং আরও ভাল ত্রুটির বার্তা সরবরাহ করবে। ইতিমধ্যে গুগল পেয়ারা ব্যবহার করা সহপাঠীদের জন্য একটি পরামর্শ হিসাবে।
টিম বাথ

2
আমি এই ধারণাটি একটি শ্রেণিতে গুটিয়ে রেখেছি
gist.github.com/denov/a7eac36a3cda041f8afeabcef09d16fc

1
@ লোনলি নিউরন দয়া করে আমার কোডটি সম্পাদনা করবেন না। এটি আমাকে এমন পরিস্থিতিতে ফেলেছে যেখানে আমার পুরো উত্তরটি যাচাই করা দরকার, যা আমি চার বছর আগে লিখেছি এবং এখনই আমার পক্ষে ঠিক এই মুহূর্তে সময় নেই।
স্কিওই

2
@ স্কিভি: একাকী সম্পাদনা সহায়ক এবং সঠিক ছিল, তাই আমি পর্যালোচনা শেষে এটি পুনরায় ইনস্টল করেছিলাম। আজ এই উত্তরটি দেখার লোকেরা আপনার উত্তরটি কীভাবে এসেছিল সে বিষয়ে চিন্তা করে না, তাদের পুরানো সংস্করণ এবং নতুন সংস্করণ এবং একটি আপডেট বিভাগ দেখার দরকার নেই। এটি আপনার উত্তরটিকে আরও বিভ্রান্তিকর এবং কম সহায়ক করে তুলেছে। চূড়ান্ত অবস্থায় পোস্টগুলি রাখা আরও ভাল এবং যদি লোকেরা এটি দেখতে পারা যায় তবে তারা পোস্টের ইতিহাসটি দেখতে পাবে।
মার্টিজন পিটারস

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
আমি এটির ব্রেভিটি পছন্দ করি এবং প্রতিটি বার যখন এটি বলা হয় তখন এটি একটি অপ্রয়োজনীয় তালিকা উদাহরণ তৈরি করা এড়াতে পছন্দ করে।
লর্ডঅফ দ্য পিপস 23'18

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 ছিল কিনা তাতে কী পার্থক্য হবে? যদি এটি 1 এর চেয়ে বেশি হয়
ryantage

18
এটি যদি দ্বিতীয় ম্যাচটি খুঁজে পায় তবে তা বন্ধ হয়ে যায়। আরও অভিনব সংগ্রহকারীরা কেবল এটিই আরও কোড ব্যবহার করে যা করেন। :-)
স্টুয়ার্ট 3

10
কীভাবে যুক্ত করবেনCollectors.collectingAndThen(toList(), l -> { if (l.size() == 1) return l.get(0); throw new RuntimeException(); })
লুকাশ এদার

1
Javadoc এই সম্পর্কে সীমা এর PARAM বলেছেন: maxSize: the number of elements the stream should be limited to। সুতরাং, এটি .limit(1)পরিবর্তে থাকা উচিত নয় .limit(2)?
অ্যালেক্সবিট

5
@alexbt সমস্যা বিবরণী হ'ল এটি নিশ্চিত করতে হয় যে ঠিক এক (কোনও বেশি, কম নয়) মিল রয়েছে। আমার কোডের পরে, result.size()এটি 1 টির সমান হয় তা নিশ্চিত করে পরীক্ষা করতে পারে it's এটি যদি 2 হয়, তবে একের বেশি ম্যাচ রয়েছে, সুতরাং এটি একটি ত্রুটি। কোডটি যদি এর পরিবর্তে না করে limit(1)থাকে তবে একাধিক ম্যাচের ফলস্বরূপ একটি একক উপাদান তৈরি হবে, যা একেবারে এক ম্যাচ হওয়ার কারণে আলাদা করা যায় না। এটি ওপি সম্পর্কে উদ্বিগ্ন একটি ত্রুটির ক্ষেত্রে মিস করবে।
স্টুয়ার্ট 20

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পছন্দ মতো এটি পুনরায় ব্যবহার করতে পারেন।


@ স্কিওই এর সিঙ্গলটন সংগ্রাহক এর চেয়ে অনুসরণ করা আরও সহজ এবং সহজ ছিল, এই কারণেই আমি তাকে এই চেকটি দিয়েছি। তবে উত্তরে sensক্যমত্য দেখতে ভাল লাগল: একটি রীতিনীতি Collectorছিল চলার উপায়।
ryantage

1
যথেষ্ট ফর্সা। আমি প্রাথমিকভাবে গতির লক্ষ্যে ছিলাম, সংক্ষিপ্ততার জন্য নয়।
লুই ওয়াসারম্যান 20

1
হ্যাঁ? তোমার দ্রুত কেন?
ryantage

3
বেশিরভাগ ক্ষেত্রে যেহেতু অল-আপ বরাদ্দ করা Listএকক পরিবর্তনীয় রেফারেন্সের চেয়ে বেশি ব্যয়বহুল।
লুই ওয়াসারম্যান

1
@ লুইসওয়াসারম্যান, চূড়ান্ত আপডেটের বাক্যটি MoreCollectors.onlyElement()আসলে প্রথম হওয়া উচিত (এবং সম্ভবত এটিই একমাত্র :))
পাইওটার ফাইন্ডেইসেন

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 এর অংশ
কেরুব

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শূন্য বা একাধিক উপাদান রয়েছে কিনা তা নিক্ষেপ করে পেয়ারাতে একটিমাত্র উপাদান পাওয়া ও নিতে একটি সুবিধাজনক পদ্ধতি রয়েছে যা এখানে নীচের এন -1 লাইনগুলি প্রতিস্থাপন করতে পারে।


4
পেয়ারার পদ্ধতি: Iterators.getOnlyElement (Iterator <T> iterator)।
আর

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

যা ছুড়ে a java.lang.IllegalStateException: Queue full তবে এটি খুব হ্যাকিং মনে হয়।

অথবা আপনি একটি reductionচ্ছিকের সাথে মিলিত হ্রাস ব্যবহার করতে পারেন:

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

হ্রাস মূলত ফিরে আসে:

  • কোনও ব্যবহারকারীর সন্ধান না হলে নাল
  • কেবলমাত্র একজনকে যদি পাওয়া যায়
  • একাধিক পাওয়া গেলে ব্যতিক্রম ছুঁড়ে

ফলাফলটি তখন একটি alচ্ছিকভাবে মোড়ানো হয়।

তবে সহজ সমাধানটি হ'ল কেবল কোনও সংগ্রহ সংগ্রহ করা, এটির আকার 1 কিনা তা পরীক্ষা করে একমাত্র উপাদান পান।


1
nullব্যবহার আটকাতে আমি একটি পরিচয় উপাদান যুক্ত করব get()। দুঃখজনকভাবে আপনার reduceকাজটি যেমনটি মনে হয় ঠিক তেমন কাজ করছে না, এমন একটি উপাদান বিবেচনা করুন Streamযার nullমধ্যে এটির উপাদান রয়েছে, সম্ভবত আপনি মনে করেন যে আপনি এটি coveredেকে রেখেছিলেন, তবে আমি হতে পারি [User#1, null, User#2, null, User#3], এখন আমার মনে হয় এটি ব্যতীত ছুঁড়ে ফেলা হবে না, যদি না আমি এখানে ভুল না করি।
স্কিওইউ

2
@ স্কিভি যদি নাল উপাদান থাকে তবে ফিল্টারটি প্রথমে একটি এনপিই ফেলে দেয়।
অ্যাসিলিয়াস

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

ব্যবহার হ্রাস

এটি আমি খুঁজে পেয়েছি সবচেয়ে সহজ এবং নমনীয় উপায় (@ প্রত্যুত্তর উত্তরের উপর ভিত্তি করে)

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

এইভাবে আপনি প্রাপ্ত:

  • ptionচ্ছিক - সর্বদা আপনার বস্তুর সাথে বা Optional.empty() উপস্থিত না থাকলে
  • যদি একাধিক উপাদান থাকে তবে ব্যতিক্রম (অবশেষে আপনার কাস্টম প্রকার / বার্তা সহ)

6

আমি মনে করি এইভাবে আরও সহজ:

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

4
এটি কেবল প্রথম খুঁজে পাওয়া যায় তবে
কেসটি

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

আমরা আরএক্সজেভা ব্যবহার করতে পারি (খুব শক্তিশালী প্রতিক্রিয়াশীল এক্সটেনশন লাইব্রেরি)

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("")আরও সাধারণ আচরণ রয়েছে।
glglgl

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

ঝরঝরে! > 1 টি উপাদানের জন্য এবং NoSuchElementException` (in ) এর জন্য 0 টি উপাদান onlyOne()ছুড়ে দেয় । IllegalStateExceptionOptional::get
simon04

@ simon04 আপনি পদ্ধতিগুলির উপর একটি নিতে জমিদার পারে Supplierএর (Runtime)Exception
জাভেয়ের ডুরি

1

আপনি যদি একটি 3rd পার্টি লাইব্রেরি ব্যবহার করে, কিছু মনে না করেন SequenceMথেকে সাইক্লপ্স-স্ট্রিম (এবং LazyFutureStreamথেকে সহজ-প্রতিক্রিয়া ) উভয় একটি একক ও singleOptional অপারেটার আছে।

singleOptional()এর মধ্যে উপাদানগুলির 0চেয়ে বেশি বা তার বেশি থাকলে একটি ব্যতিক্রম ছুঁড়ে , অন্যথায় এটি একক মান প্রদান করে।1Stream

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/Stream.html


3
বলা হয়েছিল যে count()এটি ব্যবহার করা ভাল নয় কারণ এটি টার্মিনাল অপারেশন।
রাইভ্যান্টেজ

যদি এটি সত্যিই একটি উদ্ধৃতি হয় তবে দয়া করে আপনার উত্স যুক্ত করুন
নিউরন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.