স্ট্রিম <T> আইটেবল <টি> প্রয়োগ করে না কেন?


261

জাভা 8-তে আমাদের ক্লাস স্ট্রিম <T> রয়েছে , যা কৌতূহলীভাবে একটি পদ্ধতি আছে

Iterator<T> iterator()

সুতরাং আপনি আশা করতে পারেন এটি ইন্টারফেস আইটেবল <T> বাস্তবায়িত করবে , যার জন্য ঠিক এই পদ্ধতিটি প্রয়োজন, তবে এটি তেমন নয়।

যখন আমি ফোরচ লুপ ব্যবহার করে কোনও স্ট্রিমের মাধ্যমে পুনরাবৃত্তি করতে চাই, তখন আমাকে এর মতো কিছু করতে হবে

public static Iterable<T> getIterable(Stream<T> s) {
    return new Iterable<T> {
        @Override
        public Iterator<T> iterator() {
            return s.iterator();
        }
    };
}

for (T element : getIterable(s)) { ... }

আমি কি এখানে কিছু মিস করছি?


7
পুনরাবৃত্তির অন্যান্য 2 টি পদ্ধতি (প্রতিটি এবং স্প্লিটেটের জন্য) স্ট্রিমেও রয়েছে তা উল্লেখ করার দরকার নেই
njzk2

1
Streamপ্রত্যাশিত উত্তরাধিকারী এপিআইগুলিতে যাওয়ার জন্য এটি দরকারIterable
ঝং ইয়ু

11
একটি ভাল আইডিই (যেমন IntelliJ) আপনার কোড প্রক্রিয়া সহজ করার জন্য প্রণোদিত হবে getIterable()থেকেreturn s::iterator;
ZhongYu

23
আপনার কোনও পদ্ধতির দরকার নেই। যেখানে আপনার কাছে একটি স্ট্রিম রয়েছে এবং একটি অপরিশোধনযোগ্য চান, কেবল প্রবাহটি পাস করুন :: পুনরুক্তিকারী (বা, আপনি যদি পছন্দ করেন তবে () -> স্ট্রিম.িটরেটর ()), এবং আপনি শেষ করেছেন।
ব্রায়ান গয়েটজ

6
দুর্ভাগ্যক্রমে আমি লিখতে পারি না for (T element : stream::iterator), তাই আমি এখনও পছন্দ করতাম যদি স্ট্রিমটিও প্রয়োগ করে Iterableবা কোনও পদ্ধতি toIterable()
Thorsten

উত্তর:


197

লোকেরা ইতিমধ্যে মেলিং তালিকায় on একই প্রশ্ন করেছে ☺ মূল কারণ ইটেবারে আবারও পুনরাবৃত্তিযোগ্য অর্থসূচক রয়েছে, যদিও স্ট্রিমটি এটি নয়।

আমি মনে করি প্রধান কারণ যে Iterableপুনর্ব্যাবহার্যোগ্যতা বোঝা যায়, যেহেতু Streamএমন কিছু বিষয় যা শুধুমাত্র একবার ব্যবহার করা যেতে পারে - আরো একটি মত Iterator

যদি Streamপ্রসারিত হয় Iterableতবে বিদ্যমান কোডটি যখন তারা কোনও দ্বিতীয়বার Iterableছুঁড়ে এমন কোনও গ্রহণ করে তখন অবাক হতে পারে ।Exceptionfor (element : iterable)


22
কৌতূহলীভাবে ইতিমধ্যে জাভা 7-তে এই আচরণের সাথে কিছু পুনরাবৃত্ত রয়েছে, যেমন ডিরেক্টরীস্ট্রিম: ডাইরেক্টরি স্ট্রিমটি স্বল্প পরিসরে বিস্তৃত হলেও এটি কোনও সাধারণ-উদ্দেশ্য-বিবেচনাযোগ্য নয় কারণ এটি কেবলমাত্র একটি একক আইট্রেটারকে সমর্থন করে; দ্বিতীয় বা পরবর্তী পুনরুক্তি পেতে পুনরাবৃত্তি পদ্ধতিটি অনুরোধ করে ইলিজেলস্টেটএক্সেপশন ছুড়ে দেয়। ( openjdk.java.net/projects/nio/javadoc/java/nio/file/… )
রোম

31
দুর্ভাগ্যক্রমে কিছুই নয় Iterableযে iteratorসবসময় একাধিকবার কল করা উচিত এবং না এর ডকুমেন্টেশন নেই । এটি তাদের এমন কিছু করা উচিত। এটি আনুষ্ঠানিক নির্দিষ্টকরণের চেয়ে মানক অনুশীলনের বেশি বলে মনে হয়।
লি

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

25
সম্ভবত সেরা সমাধানটি জাভা এর পূর্বাভাস একটি Iteable <T> পাশাপাশি সম্ভাব্য একটি স্ট্রিম <T> গ্রহণ করতে পারে?
ইলিজিয়াম

3
@ লিআই মানক অনুশীলনগুলি যেমন চলতে থাকে তবে এটি বেশ শক্তিশালী।
বিজিক্লপ

160

একটি রূপান্তর করতে Streamএকটি থেকে Iterable, আপনি কি করতে পারেন

Stream<X> stream = null;
Iterable<X> iterable = stream::iterator

Streamএমন একটি পদ্ধতিতে পাস করার জন্য যা প্রত্যাশা করে Iterable,

void foo(Iterable<X> iterable)

কেবল

foo(stream::iterator) 

তবে এটি সম্ভবত মজার দেখাচ্ছে; এটি আরও কিছুটা স্পষ্ট হওয়া ভাল

foo( (Iterable<X>)stream::iterator );

66
আপনি এটি একটি লুপে ব্যবহার করতে পারেন for(X x : (Iterable<X>)stream::iterator), যদিও এটি দেখতে কুৎসিত। সত্যিই, পুরো পরিস্থিতিটি কেবল অযৌক্তিক।
আলেকসান্দ্র ডাবিনস্কি

24
@ এইচআরজেIntStream.range(0,N).forEach(System.out::println)
মাইকএফএইচ

11
আমি এই প্রসঙ্গে ডাবল কোলন বাক্য গঠন বুঝতে পারি না। stream::iteratorএবং এর মধ্যে পার্থক্য কী stream.iterator(), Iterableএটি পূর্বেরটিকে কিন্তু পরবর্তীকালের জন্য গ্রহণযোগ্য করে তোলে ?
ড্যানিয়েল সি

20
আমার উত্তর দেওয়া: Iterableএকটি কার্যকরী ইন্টারফেস, সুতরাং এটি কার্যকর করে এমন একটি ফাংশন পাস করা যথেষ্ট।
ড্যানিয়েল সি

5
এটা তোলে এর মূল্য লক্ষ করেন, এই যদি প্রাপ্তির কোড করার জন্য প্রচেষ্টার সংখ্যা Iterable পুনঃ-ব্যবহার করে ভঙ্গ করবে (দুই জন্য-প্রতিটি লুপ, উদাহরণস্বরূপ পৃথক), প্রতি kennytm এর উত্তর । এই প্রযুক্তিগতভাবে স্পেক বিরতি। আপনি কেবল একবারই একটি স্ট্রিম ব্যবহার করতে পারেন; আপনি বেসস্ট্রিম :: পুনরুদ্ধারকারীকে দুবার কল করতে পারবেন না। প্রথম কলটি স্ট্রিমটি সমাপ্ত করে। জাভাডোকের জন্য: "এটি একটি টার্মিনাল অপারেশন" " এই সুবিধাজনক যদি সুবিধাজনক হয়, আপনার কোড চূড়ান্ত নিয়ন্ত্রণের অধীন নয় ফলাফলের Iteable পাস করা উচিত নয়।
জেনেক্সার


8

আপনি নীচে একটি forলুপে একটি স্ট্রিম ব্যবহার করতে পারেন :

Stream<T> stream = ...;

for (T x : (Iterable<T>) stream::iterator) {
    ...
}

( এই স্নিপেটটি এখানে চালান )

(এটি একটি জাভা 8 ফাংশনাল ইন্টারফেস কাস্ট ব্যবহার করে))

(এটি উপরের কয়েকটি মন্তব্যে আচ্ছাদিত (যেমন আলেকসান্দ্র ডাবিনস্কি ), তবে আমি এটিকে আরও দৃশ্যমান করে তুলতে একটি উত্তরের দিকে টানতে চেয়েছিলাম))


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

7

kennytm বর্ণনা কারণেই এটি কোনো চিকিত্সা অনিরাপদ এর Streamএকটি হিসাবে Iterable, এবং ঝং ইয়ু একটি ওয়ার্কঅ্যারাউন্ড প্রদত্ত যে একটি ব্যবহার অনুমোদন Streamহিসেবে Iterable, একটি অনিরাপদ পদ্ধতিতে যদ্যপি। উভয় বিশ্বের সেরা পাওয়া সম্ভব: স্পেসিফিকেশন দ্বারা তৈরি সমস্ত গ্যারান্টি পূরণ করে এমন Iterableএকটি থেকে পুনরায় ব্যবহারযোগ্য ।StreamIterable

দ্রষ্টব্য: SomeTypeএখানে কোনও ধরণের প্যারামিটার নয় - আপনার এটি যথাযথ টাইপ (উদাহরণস্বরূপ String) বা প্রতিবিম্বের অবলম্বন করা উচিত

Stream<SomeType> stream = ...;
Iterable<SomeType> iterable = stream.collect(toList()):

এর একটি বড় অসুবিধা রয়েছে:

অলস পুনরাবৃত্তির সুবিধা হারাতে হবে। আপনি যদি বর্তমান থ্রেডের সমস্ত মানকে অবিলম্বে পুনরাবৃত্তি করার পরিকল্পনা করে থাকেন তবে যে কোনও ওভারহেড তুচ্ছ হবে। তবে, আপনি যদি আংশিক বা অন্য কোনও থ্রেডে পুনরাবৃত্তি করার পরিকল্পনা করেন তবে এই তাত্ক্ষণিক এবং সম্পূর্ণ পুনরাবৃত্তির অনিচ্ছাকৃত পরিণতি হতে পারে।

অবশ্যই বড় সুবিধাটি হ'ল আপনি এটি পুনরায় ব্যবহার করতে পারবেন Iterable, যেখানে (Iterable<SomeType>) stream::iteratorকেবলমাত্র একটি একক ব্যবহারের অনুমতি দেওয়া হবে। যদি প্রাপ্তি কোডটি সংগ্রহের মাধ্যমে একাধিকবার পুনরাবৃত্তি হয় তবে এটি কেবল প্রয়োজনীয় নয়, তবে সম্ভবত কার্য সম্পাদনের পক্ষে উপকারী।


1
আপনি কি উত্তর দেওয়ার আগে আপনার কোডটি সংকলনের চেষ্টা করেছেন? এটি কাজ করে না।
তাগীর বলিভ

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

2
@ তাগিরওয়ালিভ আমি এটি আবার পরীক্ষা করে নিলাম ইন্টেলিজিতে। এটি প্রদর্শিত হয় যে ইনটেলিজ কখনও কখনও এই বাক্য গঠন দ্বারা বিভ্রান্ত হয়; আমি সত্যিই এটির জন্য একটি নিদর্শন পাইনি। তবে কোডটি সূক্ষ্মভাবে সংকলন করে এবং ইন্টেলিজি সংকলনের পরে ত্রুটি বিজ্ঞপ্তিটি সরিয়ে দেয়। আমার ধারণা এটি কেবল একটি বাগ।
জেনেক্সার

1
Stream.toArray()একটি অ্যারে না, একটি নয় Iterable, তাই এই কোডটি এখনও সংকলন করে না। তবে এটি
গ্রহণে

1
@ জেনেক্সার আপনি কীভাবে একটি ইরেটেবলের জন্য একটি অ্যারে বরাদ্দ করতে সক্ষম হন?
র‌্যাডিয়েন্টরাজোর

3

Streamবাস্তবায়ন করে না Iterable। এর সাধারণ বোধগম্যতা Iterableহ'ল এমন কিছু যা বার বার পুনরাবৃত্তি হতে পারে। Streamপুনরায় খেলতে পারা যায় না।

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

    Supplier<Stream<Integer>> streamSupplier = () -> Stream.of(10);
    Iterable<Integer> iterable = () -> streamSupplier.get().iterator();
    for(int i : iterable) {
        System.out.println(i);
    }
    // Can iterate again
    for(int i : iterable) {
        System.out.println(i);
    }

2

আপনি যদি তৃতীয় পক্ষের গ্রন্থাগারগুলি ব্যবহার করতে আপত্তি করেন না সাইক্লোপস- রিঅ্যাক্ট একটি স্ট্রিমকে সংজ্ঞায়িত করে যা স্ট্রিম এবং আইট্রেবল উভয়ই প্রয়োগ করে এবং পুনরায় খেলতে সক্ষম ( বর্ণিত কেনেটিম সমস্যাটি সমাধান করে )।

 Stream<String> stream = ReactiveSeq.of("hello","world")
                                    .map(s->"prefix-"+s);

বা: -

 Iterable<String> stream = ReactiveSeq.of("hello","world")
                                      .map(s->"prefix-"+s);

 stream.forEach(System.out::println);
 stream.forEach(System.out::println);

[প্রকাশ আমি সাইক্লোপস-রিএ্যাক্টের প্রধান বিকাশকারী]


0

নিখুঁত নয়, তবে কাজ করবে:

iterable = stream.collect(Collectors.toList());

নিখুঁত নয় কারণ এটি স্ট্রিম থেকে সমস্ত আইটেম আনবে এবং এগুলিতে রাখবে List, যা হুবহু Iterableএবং ঠিক কী নয় Stream। তাদের অলস হওয়ার কথা ।


-1

আপনি Stream<Path>এই জাতীয় ফোল্ডারে সমস্ত ফাইলের মাধ্যমে পুনরাবৃত্তি করতে পারেন :

Path path = Paths.get("...");
Stream<Path> files = Files.list(path);

for (Iterator<Path> it = files.iterator(); it.hasNext(); )
{
    Object file = it.next();

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