মধ্যবর্তী স্ট্রিম অপারেশনগুলি গণনা অনুযায়ী মূল্যায়ন করা হয় না


33

মনে হচ্ছে জাভা কীভাবে স্ট্রিম পাইপলাইনে স্ট্রিম অপারেশনগুলি রচনা করে তা বুঝতে সমস্যা হচ্ছে।

নিম্নলিখিত কোডটি কার্যকর করার সময়

public
 static void main(String[] args) {
    StringBuilder sb = new StringBuilder();

    var count = Stream.of(new String[]{"1", "2", "3", "4"})
            .map(sb::append)
            .count();

    System.out.println(count);
    System.out.println(sb.toString());
}

কনসোলটি কেবল প্রিন্ট করে 4StringBuilderসে আপত্তি এখনও মূল্য আছে ""

আমি যখন ফিল্টার অপারেশন যুক্ত করি: filter(s -> true)

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();

    var count = Stream.of(new String[]{"1", "2", "3", "4"})
            .filter(s -> true)
            .map(sb::append)
            .count();

    System.out.println(count);
    System.out.println(sb.toString());
}

আউটপুট এতে পরিবর্তিত হয়:

4
1234

এই আপাতদৃষ্টিতে অপ্রয়োজনীয় ফিল্টার অপারেশনটি কীভাবে রচিত স্ট্রিম পাইপলাইনটির আচরণ পরিবর্তন করে?


2
মজাদার !!!
uneq95

3
আমি ভাবব এটি বাস্তবায়ন-নির্দিষ্ট আচরণ; সম্ভবত এটি কারণ প্রথম স্ট্রিমটির একটি পরিচিত আকার রয়েছে তবে দ্বিতীয়টি এটির নয় এবং আকারযুক্ত নেস অন্তর্বর্তী ক্রিয়াকলাপগুলি কার্যকর করা হবে কিনা তা নির্ধারণ করে।
অ্যান্ডি টার্নার

আগ্রহের বাইরে, আপনি যদি ফিল্টার এবং মানচিত্রের বিপরীত হন তবে কী ঘটে?
অ্যান্ডি টার্নার

হাসকেলে কিছুটা প্রোগ্রাম করার পরে কিছুটা অলস মূল্যায়নের মতো এখানে কিছুটা গন্ধ লাগে। একটি গুগল অনুসন্ধান ফিরে এসেছে, সেই স্ট্রিমগুলির প্রকৃতপক্ষে কিছুটা অলসতা রয়েছে। কেস হতে পারে? এবং একটি ফিল্টার ছাড়াই, জাভা যদি যথেষ্ট চালাক হয় তবে ম্যাপিংটি বাস্তবায়িত করার দরকার নেই।
ফ্রেডেরিক

@ অ্যান্ডি টুরনার এটি একই ফলাফল দেয়, এমনকি বিপরীতে
uneq95

উত্তর:


39

count()টার্মিনাল অপারেশন JDK এর আমার সংস্করণে, নিম্নলিখিত কোড নির্বাহ শেষ পর্যন্ত:

if (StreamOpFlag.SIZED.isKnown(helper.getStreamAndOpFlags()))
    return spliterator.getExactSizeIfKnown();
return super.evaluateSequential(helper, spliterator);

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

অন্যদিকে, আপনার যদি কেবল map()পাইপলাইনে থাকে তবে স্ট্রিমের উপাদানগুলির সংখ্যা প্রাথমিক উপাদানগুলির সংখ্যার সমান হওয়ার নিশ্চয়তা দেয়। সুতরাং যদি ব্লকটি কার্যকর করা হয় এবং মধ্যবর্তী ক্রিয়াকলাপগুলি মূল্যায়ন না করেই আকারটি সরাসরি ফিরে আসে।

নোট করুন যে ল্যাম্বদা map()ডকুমেন্টেশনে সংজ্ঞায়িত চুক্তিকে লঙ্ঘন করেছে: এটি একটি হস্তক্ষেপহীন, রাষ্ট্রবিহীন অপারেশন বলে মনে করা হচ্ছে, তবে এটি রাষ্ট্রহীন নয়। সুতরাং উভয় ক্ষেত্রেই পৃথক ফলাফল হওয়া বাগ হিসাবে বিবেচনা করা যায় না।


কারণ flatMap()উপাদানগুলির সংখ্যা পরিবর্তন করতে সক্ষম হতে পারে, কারণ এটি প্রাথমিক কারণেই আগ্রহী (এখন অলস)? সুতরাং, বিকল্পটি forEach()হ'ল map()এটির বর্তমান আকারে চুক্তি লঙ্ঘন করা হলে আলাদাভাবে গণনা করা এবং গণনা করা ।
ফ্রেডেরিক

3
ফ্ল্যাটম্যাপ সম্পর্কে, আমি এটি মনে করি না। এটি ছিল, আফাইক, কারণ এটি উত্সাহী করা সহজ সূচনা ছিল। হ্যাঁ, পার্শ্ব প্রতিক্রিয়া তৈরি করতে মানচিত্র () সহ একটি স্ট্রিম ব্যবহার করা একটি খারাপ ধারণা।
জেবি নিজেট

4 1234অতিরিক্ত ফিল্টার ব্যবহার না করে বা মানচিত্রের () অপারেশনে পার্শ্ব প্রতিক্রিয়া তৈরি না করে কীভাবে পুরো আউটপুট অর্জন করবেন সে সম্পর্কে আপনার কোনও পরামর্শ আছে ?
আটলান্টাস

1
int count = array.length; String result = String.join("", array);
জেবি নিজেট

1
অথবা আপনি যদি সত্যই স্ট্রিং বিল্ডার ব্যবহার করতে চান তবে আপনি প্রত্যেকের জন্য ব্যবহার করতে পারেন, বা আপনি ব্যবহার করতে পারেনCollectors.joining("")
njzk2

19

ইন JDK -9 স্পষ্ট জাভা ডক্সে নথিভুক্ত করা হয়েছিল

পার্শ্ব-প্রতিক্রিয়াগুলির এলিডিংও অবাক হতে পারে। প্রতিটি এবং forEachOrried জন্য টার্মিনাল অপারেশনগুলি বাদ দিয়ে, আচরণের পরামিতিগুলির পার্শ্ব-প্রতিক্রিয়া সর্বদা কার্যকর করা যায় না যখন স্ট্রিম বাস্তবায়ন গণনার ফলাফলকে প্রভাবিত না করে আচরণগত পরামিতিগুলির কার্যকারিতা অপসারণ করতে পারে। (নির্দিষ্ট উদাহরণের জন্য কাউন্ট অপারেশনে ডকুমেন্টেড এপিআই নোট দেখুন see )

এপিআই নোট:

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

 List<String> l = Arrays.asList("A", "B", "C", "D");
 long count = l.stream().peek(System.out::println).count();

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


0

এটি ম্যাপের জন্য নয়। "কিছু" এর একটি ধারা "সামথিং অন্য কিছু" এর স্ট্রিমে পরিণত করার জন্য এটি ব্যবহার করা হয়েছিল বলে মনে করা হচ্ছে। এই ক্ষেত্রে, আপনি একটি বাহ্যিক স্ট্রিংবিল্ডারের সাথে একটি স্ট্রিং যুক্ত করতে মানচিত্র ব্যবহার করছেন, এর পরে আপনার কাছে "স্ট্রিংবিল্ডার" একটি স্ট্রিম রয়েছে, যার প্রত্যেকটি মানচিত্র অপারেশন দ্বারা তৈরি হয়েছিল একটি নম্বর মূল স্ট্রিংবিল্ডারের সাথে যুক্ত করে।

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

ফিল্টার এটিকে স্ট্রিমের সামগ্রীগুলি চালিত করতে বাধ্য করে যেহেতু এখন এটি প্রতিটি স্ট্রিম উপাদানটির সাথে ধারণামূলকভাবে অর্থপূর্ণ কিছু করতে হবে has

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