কালেকশন.স্ট্রিম () .এক () এবং কালেকশন.ফোরেচ () এর মধ্যে পার্থক্য কী?


286

আমি বুঝতে পারি যে এর সাহায্যে .stream()আমি চেইন অপারেশনগুলি .filter()সমান্তরাল স্ট্রিমের মতো বা ব্যবহার করতে পারি । তবে যদি আমার ছোট অপারেশনগুলি প্রয়োগ করা প্রয়োজন (উদাহরণস্বরূপ, তালিকার উপাদানগুলি মুদ্রণ করা) তবে তাদের মধ্যে পার্থক্য কী?

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

উত্তর:


287

উদাহরণস্বরূপ একটি সাধারণ ক্ষেত্রে যেমন বেশিরভাগ ক্ষেত্রে একই থাকে। তবে, বেশ কয়েকটি সূক্ষ্ম পার্থক্য রয়েছে যা উল্লেখযোগ্য হতে পারে।

একটি ইস্যু অর্ডার নিয়ে। সাথে Stream.forEach, ক্রমটি অপরিজ্ঞাত । অনুক্রমিক স্ট্রিমগুলির সাথে এটি সংঘটিত হওয়ার সম্ভাবনা নেই, তবুও এটি Stream.forEachকিছু স্বেচ্ছাসেবী ক্রমে কার্যকর করার জন্য নির্দিষ্টকরণের মধ্যে রয়েছে । এটি সমান্তরাল প্রবাহে ঘন ঘন ঘটে। বিপরীতে, Iterable.forEachসর্বদা এর পুনরাবৃত্তির ক্রমে কার্যকর করা হয় Iterable, যদি কোনও নির্দিষ্ট করা থাকে।

আরও একটি সমস্যা পার্শ্ব প্রতিক্রিয়া নিয়ে। কর্ম উল্লেখিত Stream.forEachহতে প্রয়োজন বোধ করা হয় অ হস্তক্ষেপ । ( Java.util.stream প্যাকেজ ডক দেখুন )) Iterable.forEachসম্ভাব্যভাবে কম বাধা রয়েছে। সংগ্রহগুলির জন্য java.util, Iterable.forEachসাধারণত সেই সংগ্রহটি ব্যবহার করা হবে Iterator, যার বেশিরভাগই ব্যর্থ-দ্রুত ডিজাইনের জন্য তৈরি হয়েছে এবং যা ConcurrentModificationExceptionপুনরাবৃত্তির সময় সংগ্রহটি কাঠামোগতভাবে সংশোধন করা হলে তা ছুঁড়ে দেয়। তবে রূপান্তরগুলি যা কাঠামোগত নয় করছে পুনরাবৃত্তির সময় অনুমোদিত। উদাহরণস্বরূপ, অ্যারেলিস্ট ক্লাস ডকুমেন্টেশন বলছে "কেবল কোনও উপাদানের মান নির্ধারণ করা কোনও কাঠামোগত পরিবর্তন নয়।" সুতরাং, জন্য পদক্ষেপArrayList.forEachArrayListসমস্যা ছাড়াই অন্তর্নিহিত মানগুলিতে সেট করার অনুমতি দেওয়া হয় ।

সমবর্তী সংগ্রহগুলি আবার আলাদা different ব্যর্থগতির পরিবর্তে এগুলি দুর্বলভাবে সামঞ্জস্যপূর্ণ করার জন্য ডিজাইন করা হয়েছে । সম্পূর্ণ সংজ্ঞাটি সেই লিঙ্কটিতে। সংক্ষেপে, বিবেচনা করুন ConcurrentLinkedDeque। কর্ম তার প্রেরণ forEachপদ্ধতি হয় অন্তর্নিহিত deque সংশোধন করার অনুমতি দেওয়া এমনকি গঠনের দিক, এবং ConcurrentModificationExceptionনিক্ষিপ্ত হয় না। যাইহোক, সংশোধন ঘটে যা এই পুনরাবৃত্তিতে প্রদর্শিত হতে পারে বা নাও হতে পারে। (অতএব "দুর্বল" ধারাবাহিকতা))

আরও একটি পার্থক্য দৃশ্যমান হয় যদি Iterable.forEachএকটি সিঙ্ক্রোনাইজ করা সংগ্রহের মাধ্যমে পুনরাবৃত্তি হয়। এই ধরনের সংকলনে, Iterable.forEach সংগ্রহের লক একবার নেয় এবং সমস্ত কলগুলি অ্যাকশন পদ্ধতিতে ধরে রাখে। Stream.forEachকল সংগ্রহ এর spliterator, যা লক করে না ব্যবহার করে, এবং যা অ হস্তক্ষেপ নিয়ন্ত্রক নিয়ম উপর নির্ভর করে। স্ট্রিমটির ব্যাক করা সংগ্রহটি পুনরাবৃত্তির সময় সংশোধন করা যেতে পারে এবং যদি এটি হয় তবে কোনও ConcurrentModificationExceptionবা অসামঞ্জস্যপূর্ণ আচরণের ফলাফল হতে পারে।


Iterable.forEach takes the collection's lock। কোথা থেকে এই তথ্য? আমি জেডিকে সূত্রে এ জাতীয় আচরণ খুঁজে পাচ্ছি না।
টার্বানফ

9
উদাহরণস্বরূপ hg.openjdk.java.net/jdk8/jdk8/jdk/file/jdk8-b132/src/share/… দেখুন ।
স্টুয়ার্ট

@ স্টুয়ার্ট, আপনি কি হস্তক্ষেপ না করার বিষয়ে বিস্তারিত বর্ণনা করতে পারেন? স্ট্রিম.এফ.এচ () কমকেনারমোডিশনএক্সেপশন (কমপক্ষে আমার জন্য )ও ফেলে দেবে।
yuranos

1
@ yuranos87 অনেকগুলি সংগ্রহ যেমন ArrayListসমবর্তী পরিবর্তনের জন্য মোটামুটি কঠোর চেক আছে এবং তাই প্রায়শই নিক্ষেপ করা হবে ConcurrentModificationException। তবে এটি গ্যারান্টিযুক্ত নয়, বিশেষত সমান্তরাল স্ট্রিমগুলির জন্য। সিএমই এর পরিবর্তে আপনি একটি অপ্রত্যাশিত উত্তর পেতে পারেন। স্ট্রিম উত্সে অ-কাঠামোগত পরিবর্তনগুলিও বিবেচনা করুন। সমান্তরাল স্ট্রিমগুলির জন্য, আপনি জানেন না কোন থ্রেড কোনও নির্দিষ্ট উপাদানকে প্রক্রিয়া করবে, না এটি সংশোধন করার সময় প্রক্রিয়াজাত করা হয়েছে কিনা। এটি একটি দৌড় শর্ত সেট করে, যেখানে আপনি প্রতিটি রানে বিভিন্ন ফলাফল পেতে পারেন এবং কোনও সিএমই পাবেন না।
স্টুয়ার্ট

30

এই উত্তরটি লুপগুলির বিভিন্ন বাস্তবায়নের কর্মক্ষমতা নিয়ে নিজেকে উদ্বেগ দেয়। এটি কেবলমাত্র লুপগুলির জন্য প্রান্তিকভাবে প্রাসঙ্গিক that বেশিরভাগ ক্ষেত্রে লুপের সামগ্রীটি সবচেয়ে ব্যয়বহুল উপাদান হবে be আপনি প্রায়শই লুপ করেন এমন পরিস্থিতিতে, এটি এখনও আগ্রহী হতে পারে।

আপনার লক্ষ্য নির্ধারণী সিস্টেমের অধীনে এই পরীক্ষাগুলি পুনরাবৃত্তি করা উচিত কারণ এটি প্রয়োগের নির্দিষ্ট, ( পুরো উত্স কোড )।

আমি একটি দ্রুত লিনাক্স মেশিনে 1.8.0_111 খুলুন।

আমি একটি পরীক্ষা লিখেছি যা বিভিন্ন কোডের integers(10 ^ 0 -> 10 ^ 5 এন্ট্রি) সহ বিভিন্ন কোড ব্যবহার করে একটি তালিকাতে 10 List বার লুপ করে ^

ফলাফলগুলি নীচে রয়েছে, তালিকায় প্রবেশের পরিমাণের উপর নির্ভর করে দ্রুততম পদ্ধতিটি পরিবর্তিত হয়।

তবে এখনও সবচেয়ে খারাপ পরিস্থিতিতে, 10 ^ 5 টির বেশি লুপ করা 10 ^ 6 বার সবচেয়ে খারাপ অভিনয়কারীর জন্য 100 সেকেন্ড সময় নিয়েছে, সুতরাং অন্যান্য পরিস্থিতিতে কার্যত সমস্ত পরিস্থিতিতে আরও গুরুত্বপূর্ণ।

public int outside = 0;

private void forCounter(List<Integer> integers) {
    for(int ii = 0; ii < integers.size(); ii++) {
        Integer next = integers.get(ii);
        outside = next*next;
    }
}

private void forEach(List<Integer> integers) {
    for(Integer next : integers) {
        outside = next * next;
    }
}

private void iteratorForEach(List<Integer> integers) {
    integers.forEach((ii) -> {
        outside = ii*ii;
    });
}
private void iteratorStream(List<Integer> integers) {
    integers.stream().forEach((ii) -> {
        outside = ii*ii;
    });
}

এখানে আমার সময়গুলি: মিলিসেকেন্ড / ফাংশন / তালিকায় প্রবেশের সংখ্যা। প্রতিটি রান 10 ^ 6 লুপ হয়।

                           1    10    100    1000    10000
       iterator.forEach   27   116    959    8832    88958
               for:each   53   171   1262   11164   111005
         for with index   39   112    920    8577    89212
iterable.stream.forEach  255   324   1030    8519    88419

আপনি যদি পরীক্ষার পুনরাবৃত্তি করেন তবে আমি সম্পূর্ণ উত্স কোড পোস্ট করেছি । দয়া করে এই উত্তরটি সম্পাদনা করুন এবং পরীক্ষিত সিস্টেমের একটি স্বরলিপি দিয়ে ফলাফল যুক্ত করুন।


একটি ম্যাকবুক প্রো, 2.5 গিগাহার্টজ ইন্টেল কোর আই 7, 16 জিবি, ম্যাকস 10.12.6 ব্যবহার করুন:

                           1    10    100    1000    10000
       iterator.forEach   27   106   1047    8516    88044
               for:each   46   143   1182   10548   101925
         for with index   49   145    887    7614    81130
iterable.stream.forEach  393   397   1108    8908    88361

জাভা 8 হটস্পট ভিএম - 3.4GHz ইন্টেল শিওন, 8 জিবি, উইন্ডোজ 10 প্রো

                            1    10    100    1000    10000
        iterator.forEach   30   115    928    8384    85911
                for:each   40   125   1166   10804   108006
          for with index   30   120    956    8247    81116
 iterable.stream.forEach  260   237   1020    8401    84883

জাভা ১১ হটস্পট ভিএম - ৩.৪ গিগাহার্টজ ইন্টেল শিওন, ৮ জিবি, উইন্ডোজ 10 প্রো
(উপরের মতো একই মেশিন, বিভিন্ন জেডিকে সংস্করণ)

                            1    10    100    1000    10000
        iterator.forEach   20   104    940    8350    88918
                for:each   50   140    991    8497    89873
          for with index   37   140    945    8646    90402
 iterable.stream.forEach  200   270   1054    8558    87449

জাভা 11 ওপেনজে 9 ভিএম - 3.4GHz ইন্টেল শিওন, 8 গিগাবাইট, উইন্ডোজ 10 প্রো
(একই মেশিন এবং জেডিকে সংস্করণ উপরে, বিভিন্ন ভিএম)

                            1    10    100    1000    10000
        iterator.forEach  211   475   3499   33631   336108
                for:each  200   375   2793   27249   272590
          for with index  384   467   2718   26036   261408
 iterable.stream.forEach  515   714   3096   26320   262786

জাভা 8 হটস্পট ভিএম - 2.8GHz এএমডি, 64 জিবি, উইন্ডোজ সার্ভার 2016

                            1    10    100    1000    10000
        iterator.forEach   95   192   2076   19269   198519
                for:each  157   224   2492   25466   248494
          for with index  140   368   2084   22294   207092
 iterable.stream.forEach  946   687   2206   21697   238457

জাভা ১১ হটস্পট ভিএম - ২.৮ গিগাহার্টজ এএমডি, GB৪ জিবি, উইন্ডোজ সার্ভার ২০১
((উপরের মতো একই মেশিন, বিভিন্ন জেডিকে সংস্করণ)

                            1    10    100    1000    10000
        iterator.forEach   72   269   1972   23157   229445
                for:each  192   376   2114   24389   233544
          for with index  165   424   2123   20853   220356
 iterable.stream.forEach  921   660   2194   23840   204817

জাভা 11 ওপেনজে 9 ভিএম - 2.8GHz এএমডি, 64 জিবি, উইন্ডোজ সার্ভার 2016
(একই মেশিন এবং জেডকে সংস্করণ উপরে, বিভিন্ন ভিএম)

                            1    10    100    1000    10000
        iterator.forEach  592   914   7232   59062   529497
                for:each  477  1576  14706  129724  1190001
          for with index  893   838   7265   74045   842927
 iterable.stream.forEach 1359  1782  11869  104427   958584

আপনি যে ভিএম নির্বাচন করেছেন তা হটস্পট / ওপেনজে 9 / ইত্যাদি ক্ষেত্রেও তাত্পর্যপূর্ণ।


3
এটি খুব সুন্দর উত্তর, ধন্যবাদ! তবে প্রথম নজরে (এবং দ্বিতীয়টি থেকে) এটিও পরিষ্কার নয় যে কোন পদ্ধতিটি কোন পরীক্ষার সাথে মিলছে।
টোরিনা

আমি মনে করি কোড উত্তরের জন্য এই উত্তরের আরও বেশি ভোট প্রয়োজন :)।
কোরি

পরীক্ষার উদাহরণগুলির জন্য +1
সেন্টোস

8

আপনি যে দুটি উল্লেখ করেছেন তার মধ্যে কোনও পার্থক্য নেই, ন্যূনতম ধারণাগতভাবে, এটি Collection.forEach()কেবল একটি শর্টহ্যান্ড।

stream()বস্তু তৈরির কারণে অভ্যন্তরীণ সংস্করণটির কিছুটা ওভারহেড রয়েছে, তবে চলমান সময়ের দিকে তাকালে এটির ওপরে কোনও ওভারহেড নেই।

উভয় বাস্তবায়ন collectionএকবারে সামগ্রীতে পুনরাবৃত্ত হয় এবং পুনরাবৃত্তির সময় উপাদানটি প্রিন্ট করে।


আপনি উল্লিখিত অবজেক্ট ক্রিয়েশনটি, আপনি কি Streamতৈরি হচ্ছে বা স্বতন্ত্র বস্তুর কথা উল্লেখ করছেন ? আফাইক, একটি Streamউপাদানগুলির সদৃশ করে না।
রাফি খাচ্চডৌরিয়ান

30
এই উত্তরটি ভদ্রলোকের দ্বারা লিখিত দুর্দান্ত উত্তরের বিরোধিতা বলে মনে হচ্ছে যারা ওরাকল কর্পোরেশনে জাভা কোর লাইব্রেরিগুলি বিকাশ করে।
দাউদ ইবনে করিম

0

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

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

list.forEach(System.out::print);
System.out.print(" ");
list.parallelStream().forEach(System.out::print);

আমরা যদি কোডটি বেশ কয়েকবার চালাই তবে আমরা দেখতে পাই যে list.forEach () আইটেমগুলি সন্নিবেশ ক্রমে প্রক্রিয়াকরণ করে, অন্যদিকে list.parallelStream ()। ForEach () প্রতিটি রানেই আলাদা ফলাফল দেয়। একটি সম্ভাব্য আউটপুট হল:

ABCD CDBA

আর একটি হ'ল:

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