আমি কখন স্রোত ব্যবহার করব?


102

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

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

অবশ্যই এটি প্রতি কঠিন কাজ নয়। তবে আমি অবাক হই যে আমার স্ট্রিম ব্যবহার করা উচিত, না (-আচ) লুপের জন্য।

ক্রমতালিকা

private static final List<String> EXCLUDE_PATHS = Arrays.asList(new String[]{
    "my/path/one",
    "my/path/two"
});

উদাহরণ - স্ট্রিম

private boolean isExcluded(String path){
    return EXCLUDE_PATHS.stream()
                        .map(String::toLowerCase)
                        .filter(path::contains)
                        .collect(Collectors.toList())
                        .size() > 0;
}

উদাহরণ - প্রতিটি লুপের জন্য

private boolean isExcluded(String path){
    for (String excludePath : EXCLUDE_PATHS) {
        if(path.contains(excludePath.toLowerCase())){
            return true;
        }
    }
    return false;
}

মনে রাখবেন যে pathপ্যারামিটারটি সর্বদা ছোট হাতের থাকে

আমার প্রথম অনুমানটি হ'ল প্রতি-প্রত্যক্ষের পদ্ধতিটি দ্রুত, কারণ শর্তটি পূরণ হলে লুপটি তত্ক্ষণাত্ ফিরে আসবে। ফিল্টারিং সম্পূর্ণ করার জন্য স্ট্রিমটি এখনও সমস্ত তালিকা এন্ট্রি থেকে লুপ করবে।

আমার ধারণা সঠিক? যদি তা হয় তবে আমি কেন (বা কখন ) stream()তখন ব্যবহার করব ?


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

12
এখানে কোন প্রয়োজন new String[]{…}নেই। কেবল ব্যবহার করুনArrays.asList("my/path/one", "my/path/two")
হলগার

4
যদি আপনার উত্সটি হয় String[]তবে কল করার দরকার নেই Arrays.asList। আপনি কেবল অ্যারে ব্যবহার করে স্ট্রিম করতে পারেন Arrays.stream(array)। যাইহোক, isExcludedপুরোপুরি পরীক্ষার উদ্দেশ্য বুঝতে আমার অসুবিধা হচ্ছে । আসলেই আকর্ষণীয় যে কোনও উপাদান EXCLUDE_PATHSআক্ষরিকভাবে কোথাও কোথাও কোথাও কোথাও অন্তর্ভুক্ত রয়েছে? অর্থাত isExcluded("my/path/one/foo/bar/baz")ফিরে আসবে trueপাশাপাশি হিসাবে, isExcluded("foo/bar/baz/my/path/one/")...
হোলগার

4
দুর্দান্ত, আমি Arrays.streamপদ্ধতিটি সম্পর্কে অবগত ছিলাম না, এটি নির্দেশ করার জন্য ধন্যবাদ। আসলে, আমি পোস্ট করা উদাহরণটি আমার ছাড়া অন্য কারও পক্ষে যথেষ্ট অকেজো বলে মনে হচ্ছে। আমি isExcludedপদ্ধতিটির আচরণ সম্পর্কে সচেতন , তবে এটি আপনার নিজের প্রশ্নের উত্তর দেওয়ার জন্য এটি কেবল আমার নিজের প্রয়োজন: হ্যাঁ , এটি আকর্ষণীয় কারণগুলির কারণে আমি উল্লেখ করতে চাই না, কারণ এটি সুযোগের সাথে খাপ খায় না would মূল প্রশ্নের।
mcuenez

4
toLowerCaseইতিমধ্যে নিম্ন-केसের ধ্রুবকটিতে কেন প্রয়োগ করা হয়? এটি pathযুক্তি প্রয়োগ করা উচিত নয় ?
সেবাস্তিয়ান রেডল

উত্তর:


80

আপনার অনুমানটি সঠিক। আপনার স্ট্রিম প্রয়োগটি লুপের চেয়ে ধীর।

এই স্ট্রিমের ব্যবহারটি লুপটির মতো দ্রুত হওয়া উচিত:

EXCLUDE_PATHS.stream()  
                               .map(String::toLowerCase)
                               .anyMatch(path::contains);

এটি আইটেমগুলির মাধ্যমে পুনরাবৃত্তি করে String::toLowerCaseএবং এক এক করে আইটেমগুলিতে ফিল্টার করে এবং ফিল্টার হয় যা মেলে প্রথম আইটেমে termin

উভয়ই collect()& anyMatch()টার্মিনাল অপারেশন। anyMatch()প্রথম পাওয়া আইটেমটি থেকে প্রস্থান করে, যদিও collect()সমস্ত আইটেমকে প্রক্রিয়া করা প্রয়োজন।


4
আশ্চর্যজনক, এর findFirst()সাথে সংমিশ্রণ সম্পর্কে জানতেন না filter()। স্পষ্টতই, আমি কীভাবে স্ট্রিমগুলি কীভাবে ব্যবহার করব তা আমি জানি না as
mcuenez

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

আপনার সম্পাদনার পরে, আমি মনে করি আপনার উত্তরটি হ'ল এটি গ্রহণ করা উচিত, যেমন আপনিও আমার উত্তরের উত্তরটির মন্তব্যে উত্তর দিয়েছেন। যদিও, আমি @ rvit34 কোডটি পোস্ট করার জন্য কিছু ক্রেডিট দিতে চাই :-)
এমকিউনেজ

34

স্ট্রিম ব্যবহার করবেন কিনা তা সিদ্ধান্ত পারফরম্যান্স বিবেচনার দ্বারা চালিত করা উচিত নয়, বরং পঠনযোগ্যতার দ্বারা। যখন এটি সত্যিই পারফরম্যান্সের দিকে আসে তখন অন্যান্য বিবেচনা রয়েছে।

আপনার .filter(path::contains).collect(Collectors.toList()).size() > 0পদ্ধতির সাথে, আপনি সমস্ত উপাদানগুলি প্রক্রিয়া করছেন এবং Listআকারের সাথে তুলনা করার আগে এগুলি একটি অস্থায়ী হিসাবে সংগ্রহ করছেন , এখনও দুটি উপাদান সমন্বিত স্ট্রিমের পক্ষে এটি খুব কমই গুরুত্বপূর্ণ।

ব্যবহারের ফলে .map(String::toLowerCase).anyMatch(path::contains)সিপিইউ চক্র এবং স্মৃতি সাশ্রয় হয়, যদি আপনার কাছে যথেষ্ট পরিমাণে উপাদান থাকে। তবুও, Stringম্যাচ না পাওয়া পর্যন্ত এটি প্রতিটিকে তার ছোট হাতের উপস্থাপনায় রূপান্তর করে । স্পষ্টতই, ব্যবহার করার একটি বিষয় রয়েছে

private static final List<String> EXCLUDE_PATHS =
    Stream.of("my/path/one", "my/path/two").map(String::toLowerCase)
          .collect(Collectors.toList());

private boolean isExcluded(String path) {
    return EXCLUDE_PATHS.stream().anyMatch(path::contains);
}

পরিবর্তে. সুতরাং আপনাকে প্রতিটি অনুরোধে লোকেচেস রূপান্তরটির পুনরাবৃত্তি করতে হবে না isExcluded। যদি উপাদানগুলির সংখ্যা EXCLUDE_PATHSবা স্ট্রিংগুলির দৈর্ঘ্য সত্যই বড় হয়ে যায়, আপনি ব্যবহার বিবেচনা করতে পারেন

private static final List<Predicate<String>> EXCLUDE_PATHS =
    Stream.of("my/path/one", "my/path/two").map(String::toLowerCase)
          .map(s -> Pattern.compile(s, Pattern.LITERAL).asPredicate())
          .collect(Collectors.toList());

private boolean isExcluded(String path){
    return EXCLUDE_PATHS.stream().anyMatch(p -> p.test(path));
}

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

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

যাইহোক, উপরের কোড উদাহরণগুলি আপনার মূল কোডটির যুক্তি রাখে, যা আমার কাছে সন্দেহজনক বলে মনে হচ্ছে। তোমার isExcludedপদ্ধতি আয় true, তাই এটি ফেরৎ যদি নির্দিষ্ট করা পাথ তালিকায় উপাদানের কোনো রয়েছে, trueএর জন্য /some/prefix/to/my/path/oneযেমন, পাশাপাশি my/path/one/and/some/suffixবা এমনকি /some/prefix/to/my/path/one/and/some/suffix

এমনকি dummy/path/onerousএটি containsস্ট্রিং হিসাবে মানদণ্ডগুলি পূরণ করা বিবেচনা করা হয় my/path/one...


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

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


21

হ্যাঁ তুমি ঠিক. আপনার স্ট্রিম পদ্ধতির কিছুটা ওভারহেড থাকবে। তবে আপনি এই ধরনের নির্মাণ ব্যবহার করতে পারেন:

private boolean isExcluded(String path) {
    return  EXCLUDE_PATHS.stream().map(String::toLowerCase).anyMatch(path::contains);
}

স্ট্রিমগুলি ব্যবহারের প্রধান কারণ হ'ল তারা আপনার কোডটিকে সহজ এবং সহজভাবে পড়তে পারে।


4
কি anyMatchজন্য একটি শর্টকাট filter(...).findFirst().isPresent()?
mcuenez

6
হ্যাঁ! এটি আমার প্রথম পরামর্শের চেয়েও ভাল।
স্টিফান প্রাইজ

8

জাভা প্রবাহের লক্ষ্য সমান্তরাল কোড লেখার জটিলতা সহজ করে তোলা। এটি কার্যকরী প্রোগ্রামিং দ্বারা অনুপ্রাণিত। সিরিয়াল স্ট্রিমটি কেবল কোড ক্লিনার করার জন্য।

আমরা যদি পারফরম্যান্স চাই তবে আমাদের প্যারালাল স্ট্রিম ব্যবহার করা উচিত যা ডিজাইন করা হয়েছিল। সিরিয়ালটি সাধারণভাবে ধীর।

সেখানে একটি ভাল নিবন্ধ সম্পর্কে পড়তে হয় , এবং পারফরমেন্স ForLoopStreamParallelStream

আপনার কোডে আমরা প্রথম ম্যাচে অনুসন্ধান বন্ধ করতে সমাপ্তির পদ্ধতিগুলি ব্যবহার করতে পারি। (যে কোনও ম্যাচ ...)


5
মনে রাখবেন যে ছোট স্ট্রিমের জন্য এবং অন্য কোনও ক্ষেত্রে সমান্তরাল স্ট্রিমটি স্টার্টআপ ব্যয়ের কারণে ধীর হতে পারে। এবং যদি আপনার কোনও অর্ডারড টানা টানা টানা টার্মিনাল অপারেশন থাকে তবে শেষদিকে পুনরায় সংশ্লেষনের জন্য।
CAD97

0

অন্যরা যেমন অনেক ভাল পয়েন্ট উল্লেখ করেছে তবে আমি কেবল স্ট্রিম মূল্যায়নে অলস মূল্যায়নের উল্লেখ করতে চাই । যখন আমরা map()লোয়ার কেস পাথগুলির একটি স্ট্রিম তৈরি করতে করি, আমরা তত্ক্ষণাত্ পুরো স্ট্রিমটি তৈরি করব না, পরিবর্তে প্রবাহটি অলসভাবে নির্মিত হয় , এজন্য পারফরম্যান্সটি লুপের জন্য traditionalতিহ্যগত সমতুল্য হওয়া উচিত। এটি একটি সম্পূর্ণ স্ক্যান করছে না, map()এবং anyMatch()একই সাথে কার্যকর করা হবে। একবার anyMatch()সত্য প্রত্যাবর্তন হলে তা সংক্ষিপ্ত-প্রচারিত হবে।

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