কেন পরিবেশনযোগ্য <টি> স্ট্রিম () এবং সমান্তরাল স্ট্রিম () পদ্ধতি সরবরাহ করে না?


241

আমি ভাবছি কেন Iterableইন্টারফেসটি stream()এবং parallelStream()পদ্ধতিগুলি সরবরাহ করে না । নিম্নলিখিত শ্রেণীর বিবেচনা করুন:

public class Hand implements Iterable<Card> {
    private final List<Card> list = new ArrayList<>();
    private final int capacity;

    //...

    @Override
    public Iterator<Card> iterator() {
        return list.iterator();
    }
}

ট্রেডিং কার্ড গেম খেলার সময় আপনার হাতে কার্ড থাকতে পারে এটি হ্যান্ডের একটি বাস্তবায়ন ।

মূলত এটি একটিকে আবৃত করে List<Card>, সর্বাধিক ক্ষমতা নিশ্চিত করে এবং কিছু অন্যান্য দরকারী বৈশিষ্ট্য সরবরাহ করে। এটি সরাসরি হিসাবে এটি বাস্তবায়ন হিসাবে ভাল List<Card>

এখন, পরিবহনের জন্য আমি ভেবেছিলাম এটি কার্যকর করা ভাল হবে Iterable<Card>, আপনি যদি লুপ করতে চান তবে আপনি লুপের জন্য বর্ধিত ব্যবহার করতে পারেন। (আমার Handক্লাসটি একটি get(int index)পদ্ধতিও সরবরাহ করে, সুতরাং এটি Iterable<Card>আমার মতে ন্যায়সঙ্গত)

Iterableইন্টারফেস নিম্নলিখিত (javadoc বাদ) প্রদান করে:

public interface Iterable<T> {
    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

এখন আপনি এই সহ একটি স্ট্রিম পেতে পারেন:

Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);

তাই আসল প্রশ্ন উপর:

  • কেন Iterable<T>বাস্তবায়ন করে এমন একটি ডিফল্ট পদ্ধতিগুলি সরবরাহ করে না stream()এবং parallelStream(), আমি এমন কিছুই দেখতে পাচ্ছি না যা এটি অসম্ভব বা অযাচিত করবে?

সম্পর্কিত যে প্রশ্নটি আমি পেয়েছি তা হ'ল নিম্নরূপ: স্ট্রিম <T> কেন পরিবেশনযোগ্য <টি> প্রয়োগ করে না?
যা অদ্ভুতভাবে এটি প্রায় কিছু অন্যান্য উপায়ে এটি করার পরামর্শ দেয়।


1
আমার ধারণা, ল্যাম্বদা মেলিং তালিকার পক্ষে এটি একটি ভাল প্রশ্ন ।
এডউইন ডালোরজো

কোনও স্ট্রিমের উপর দিয়ে পুনরাবৃত্তি করতে ইচ্ছামতো কেন বেদনা? কীভাবে আপনি সম্ভবত break;পুনরাবৃত্তি করতে পারেন ? (ঠিক আছে, Stream.findFirst()একটি সমাধান হতে পারে তবে এটি সমস্ত প্রয়োজনীয়তা পূরণ করতে পারে না ...)
glglgl

উত্তর:


298

এটি কোনও ভুল ছিল না; ২০১৩ সালের জুনে ইজি তালিকায় বিস্তারিত আলোচনা হয়েছিল।

বিশেষজ্ঞ গ্রুপের সুনির্দিষ্ট আলোচনার মূলসূত্রটি এই থ্রেডে

যদিও এটি "সুস্পষ্ট" বলে মনে হয়েছিল (এমনকি বিশেষজ্ঞ গ্রুপের কাছেও) যেটি stream()বোধগম্য হয়েছিল Iterable, তবুও যে Iterableসাধারণটি সাধারণ ছিল তা একটি সমস্যা হয়ে দাঁড়িয়েছিল, কারণ প্রকৃত স্বাক্ষর:

Stream<T> stream()

আপনি যা যা করতে চান তা সবসময় ছিল না। Iterable<Integer>পরিবর্তে কিছু জিনিস যা তাদের প্রবাহের পদ্ধতিটি ফিরে আসে IntStream, উদাহরণস্বরূপ। কিন্তু stream()এই স্তরটিকে উচ্চ স্তরের উপরে স্থাপন করাটি অসম্ভব হয়ে উঠবে। সুতরাং পরিবর্তে, আমরা এটা সত্যিই সহজ একটি করতে প্রণীত Streamএকটি থেকে Iterable, একটি প্রদানের মাধ্যমে spliterator()পদ্ধতি। stream()ইন বাস্তবায়ন Collectionঠিক:

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

যে কোনও ক্লায়েন্ট তার সাথে স্ট্রিমটি তাদের কাছে পেতে পারে Iterable:

Stream s = StreamSupport.stream(iter.spliterator(), false);

শেষ পর্যন্ত আমরা এই সিদ্ধান্তে আসেন যে যোগ stream()করার Iterableভুল হবে।


8
আমি প্রথম দেখছি, প্রশ্নের উত্তর দেওয়ার জন্য অনেক ধন্যবাদ। আমি এখনও কৌতূহল বোধ করি যদিও একটি Iterable<Integer>(আমি মনে করি আপনি কী সম্পর্কে কথা বলছেন?) একটি ফিরিয়ে দিতে চান IntStream। পুনরাবৃত্তি হবে না বরং PrimitiveIterator.OfInt? অথবা আপনি সম্ভবত অন্য ইউজকেস বলতে চান?
স্কিভি

139
আমার কাছে এই মতামতটি অদ্ভুত মনে হয়েছে যে উপরের যুক্তিটি আইটেবলের জন্য অনুমিতভাবে প্রয়োগ হয়েছিল (আমার স্ট্রিম থাকতে পারে না) কারণ কেউ এটি স্ট্রিম ফিরিয়ে দিতে চান) তবে সমান পরিমাণে চিন্তা সংগ্রহের সাথে একই একই পদ্ধতি যুক্ত করার জন্য দেওয়া হয়নি ( আমি আমার সংগ্রহে <ইন্টিজার> এর স্ট্রিমটি () এন্ট্রস্ট্রিমটিও ফিরিয়ে আনতে চাইছি) অন্যটি, এটি বেশ
চমকপ্রদ

6
ব্রায়ান ম্যাকচ্যাটন: এটি আমার কাছে আরও বোধগম্য। দেখে মনে হচ্ছে যে লোকেরা কেবল তর্ক-বিতর্ক করে ক্লান্ত হয়ে পড়েছে এবং এটিকে নিরাপদে খেলার সিদ্ধান্ত নিয়েছে।
জোনাথন লক

44
যদিও এটি উপলব্ধি করে, এমন কোনও কারণ আছে যে কোনও বিকল্প স্থিতিশীল নেই Stream.of(Iterable), যা কমপক্ষে এপিআই ডকুমেন্টেশনগুলি পড়ে পদ্ধতিটিকে যুক্তিসঙ্গতভাবে আবিষ্কারযোগ্য করে তুলবে - এমন কোনও ব্যক্তি হিসাবে যিনি সত্যই কখনও স্ট্রিমের অভ্যন্তরীণ সাথে কাজ করেননি আমি কখনও করিনি I'd এমনকি লাগছিলStreamSupport, যা "নিম্ন স্তরের অপারেশন" যে হল "বেশিরভাগ গ্রন্থাগার লেখকদের জন্য" প্রদান করে ডকুমেন্টেশন বর্নণা করা আছে।
জুলে

9
আমি জুলসের সাথে পুরোপুরি একমত স্ট্রিমসপোর্ট.স্ট্রিম (iter.spliterator (), মিথ্যা) এর পরিবর্তে একটি স্ট্যাটিক পদ্ধতি Stream.of (Iteratable iter) বা Stream.of (Iterator iter) যুক্ত করা উচিত;
ব্যবহারকারী_3380739

23

আমি প্রকল্পের বেশ কয়েকটি ল্যাম্বদা মেলিং তালিকায় তদন্ত করেছি এবং আমার মনে হয় আমি কয়েকটি আকর্ষণীয় আলোচনা পেয়েছি।

আমি এখনও পর্যন্ত সন্তোষজনক ব্যাখ্যা খুঁজে পাই না। এই সমস্ত পড়ার পরে আমি উপসংহারে পৌঁছেছি যে এটি কেবল একটি বাদ ছিল। তবে আপনি এখানে দেখতে পারেন যে এটিপিআইয়ের ডিজাইনের সময় কয়েক বছর ধরে এটি বেশ কয়েকবার আলোচিত হয়েছিল।

ল্যাম্বদা লিবস স্পেশ বিশেষজ্ঞরা

ল্যাম্বডা লিবস স্পেশ বিশেষজ্ঞের মেলিং তালিকায় আমি এই সম্পর্কে একটি আলোচনা পেয়েছি :

Iterable / Iterator.stream এর অধীনে () স্যাম পুল্লারা বলেছেন:

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

আমার পরামর্শটি অন্তত আইট্রেটারে রাখার জন্য যাতে আপনি দুটি বিশ্বের মধ্যে পরিষ্কারভাবে যেতে পারেন এবং এটি করার চেয়ে এটি সহজে আবিষ্কারযোগ্যও হবে:

স্ট্রিমস স্ট্রিম (স্প্লিটেটরস.স্প্লিটেটরঅজ্ঞাত আকার (পুনরুক্তিকারী, স্প্লিটেটর.অর্ডারড))

এবং তারপরে ব্রায়ান গোয়েজ প্রতিক্রিয়া জানিয়েছিলেন :

আমি মনে করি স্যামের বক্তব্যটি ছিল যে প্রচুর গ্রন্থাগার ক্লাস রয়েছে যা আপনাকে একটি আইট্রেটর দেয় তবে অগত্যা আপনাকে নিজের স্প্লিটেরেটর লিখতে দেবেন না। সুতরাং আপনি যা করতে পারেন তা হ'ল কল স্ট্রিম (স্প্লিটেটর ইউনডনসাইজ (রিটারেটর))। স্যাম পরামর্শ দিচ্ছে যে আমরা আপনার জন্য এটি করতে Iterator.stream () সংজ্ঞায়িত করব।

আমি লাইব্রেরি লেখক / উন্নত ব্যবহারকারীদের জন্য স্ট্রিম () এবং স্প্লিটেটর () পদ্ধতিগুলি রাখতে চাই।

এবং পরে

"একজন স্প্লিটেরেটর লেখাকে একজন ইন্টেরেটর লেখার চেয়ে সহজ বলে মনে করা হয়, আমি কেবলমাত্র একজন আইট্রেটারের পরিবর্তে একটি স্প্লিটেরেটর লিখতে পছন্দ করবো (আইট্রেটারটি 90 এর দশকের তাই :)"

যদিও আপনি বিন্দুটি মিস করছেন। এখানে লক্ষ লক্ষ ক্লাস রয়েছে যা ইতিমধ্যে আপনাকে একজন ইট্রেটর সরবরাহ করেছে। এবং তাদের অনেকগুলিই স্প্লিট্রেটার-প্রস্তুত নয়।

লাম্বদা মেলিং তালিকায় পূর্ববর্তী আলোচনা

আপনি যে উত্তরটি সন্ধান করছেন এটি এটি নাও হতে পারে তবে প্রকল্প ল্যাম্বদা মেলিং তালিকায় এটি সংক্ষেপে আলোচনা করা হয়েছিল। সম্ভবত এটি এই বিষয়ে একটি বিস্তৃত আলোচনা জোরদার করতে সহায়তা করে।

ব্রায়ান গয়েটসের কথায় স্ট্রিমস অফ ইটেবারে :

পিছপা...

স্ট্রিম তৈরির অনেকগুলি উপায় রয়েছে। উপাদানগুলি কীভাবে বর্ণনা করতে হবে সে সম্পর্কে আপনার আরও তথ্য, স্ট্রিমের গ্রন্থাগার আপনাকে আরও কার্যকারিতা এবং কার্য সম্পাদন করতে পারে। সর্বাধিক তথ্যের জন্য, তারা হ'ল:

iterator

Iterator + আকার

Spliterator

স্প্লিট্রেটার যা এর আকার জানে

স্প্লিট্রেটার যা এর আকার জানে এবং আরও জানে যে সমস্ত উপ-বিভক্তরা তাদের আকার জানেন।

(কারও কারও অবাক লাগতে পারে যে আমরা যেসব ক্ষেত্রে Q (উপাদান অনুসারে কাজ করা হয়) অনর্থক সে ক্ষেত্রেও বোবা পুনরুক্তিকারীর কাছ থেকে সমান্তরালতা বের করতে পারি))

যদি ইটারেবলের স্ট্রিম () পদ্ধতি থাকে তবে এটি কোনও আকারের কোনও তথ্য ছাড়াই একটি স্প্লিট্রেটারের সাথে একটি আইট্রেটারকে জড়িয়ে রাখবে। তবে সব চেয়ে যে Iterable হয় না আকার তথ্য নেই। যার অর্থ আমরা অভাবের স্ট্রিমগুলি পরিবেশন করছি। এটা এত ভাল না।

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

আইটেবারের দ্বারা সরবরাহ করা ডিফল্টটি সত্যই একটি কৃপণ হবে - যদিও আকারের সংখ্যাগরিষ্ঠ সংখ্যাগুরুরা এই তথ্যটি জানে না যদিও এটি আকার ফেলে দেবে।

দ্বন্দ্ব?

যদিও, দেখে মনে হচ্ছে আলোচনাটি স্ট্রিমসের প্রাথমিক নকশায় প্রাথমিকভাবে পুনরাবৃত্তকারীদের উপর ভিত্তি করে বিশেষজ্ঞ গ্রুপের যে পরিবর্তনগুলির উপর ভিত্তি করে তৈরি হয়েছিল।

তবুও, এটি লক্ষ্য করা আকর্ষণীয় যে সংগ্রহের মতো ইন্টারফেসে স্ট্রিম পদ্ধতিটি এটি হিসাবে সংজ্ঞায়িত করা হয়:

default Stream<E> stream() {
   return StreamSupport.stream(spliterator(), false);
}

যা একই আইটেমি ইন্টারফেসে ব্যবহৃত হচ্ছে একই কোড হতে পারে।

সুতরাং, এই কারণেই আমি বলেছিলাম এই উত্তরটি সম্ভবত সন্তোষজনক নয়, তবে এখনও আলোচনার জন্য আকর্ষণীয়।

রিফ্যাক্টরিং এর প্রমাণ

মেলিং তালিকায় বিশ্লেষণ অব্যাহত রেখে মনে হচ্ছে স্প্লিটআইট্রেটার পদ্ধতিটি মূলত সংগ্রহ ইন্টারফেসে ছিল এবং ২০১৩ সালের কোনও এক সময় তারা এটিকে আইটেবারে স্থানান্তরিত করে।

সংগ্রহ থেকে পর্যবেক্ষণযোগ্য পর্যন্ত স্প্লিটআইট্রেটরটি টানুন

উপসংহার / তত্ত্ব?

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

অন্যান্য কারণ থাকলে সেগুলি স্পষ্ট নয়। অন্য কারও তত্ত্ব আছে?


আমি আপনার প্রতিক্রিয়া প্রশংসা করি, কিন্তু আমি সেখানে যুক্তির সাথে একমত নই। মুহূর্ত যে আপনি ওভাররাইড এ spliterator()এর Iterable, তারপর সব বিষয় সেখানে ঠিক করা হয়েছে, এবং আপনি জাভাস্ক্রিপ্টে গার্বেজ বাস্তবায়ন করতে পারে stream()এবং parallelStream()..
skiwi

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

1
@ স্কিভি আমি অন্যান্য মেলিং তালিকা পর্যালোচনা করেছি এবং আলোচনার জন্য আরও প্রমাণ এবং সম্ভবত কিছু ধারণা পেয়েছি যা কিছু রোগ নির্ণয়ের তাত্ত্বিক করতে সহায়তা করে।
এডউইন ডালোরজো

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

6

আপনি যদি আকারটি জানেন তবে আপনি java.util.Collectionযে stream()পদ্ধতিটি সরবরাহ করে তা ব্যবহার করতে পারেন :

public class Hand extends AbstractCollection<Card> {
   private final List<Card> list = new ArrayList<>();
   private final int capacity;

   //...

   @Override
   public Iterator<Card> iterator() {
       return list.iterator();
   }

   @Override
   public int size() {
      return list.size();
   }
}

এবং তারপর:

new Hand().stream().map(...)

আমি একই সমস্যার মুখোমুখি হয়েছি এবং অবাক হয়েছি যে আমার Iterableপ্রয়োগটি খুব সহজেই পদ্ধতিটি AbstractCollectionযুক্ত করে একটি বাস্তবায়নে খুব সহজেই বাড়ানো যেতে পারে size()(ভাগ্যক্রমে আমার সংগ্রহটির আকার ছিল :-)

আপনি ওভাররাইড বিবেচনা করা উচিত Spliterator<E> spliterator()

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