স্ট্রিং.কমার্স () জাভা 8-তে অন্তর্নির্মিত একটি স্ট্রিম কেন?


197

জাভা 8, একটি নতুন পদ্ধতি String.chars()যার একটি স্ট্রিম ফেরৎ intগুলি ( IntStream) যে চরিত্র কোড প্রতিনিধিত্ব করে। আমার ধারণা অনেক লোক charএর পরিবর্তে এখানে একটি স্ট্রিম আশা করবে expect এইভাবে এপিআই ডিজাইন করার প্রেরণাটি কী ছিল?


4
@ রোহিতজাইন আমার অর্থ কোনও বিশেষ প্রবাহ নয়। যদি CharStreamনা থাকে তবে এটিকে যুক্ত করতে সমস্যা কী হবে?
আদম ডায়গা

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

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

9
@JB Nizet: আমার কাছে এটা দেখে মনে হচ্ছে আমরা ইতিমধ্যে আছে সব প্রবাহ ওভারলোডিং সেইসাথে দেওয়া ইন্টারফেস একটি বিস্ফোরণ সব ফাংশন ইন্টারফেসগুলি ...
হোলগার

5
হ্যাঁ, ইতিমধ্যে একটি বিস্ফোরণ ঘটেছে, এমনকি কেবল তিনটি আদিম স্ট্রিম বিশেষীকরণ রয়েছে। আটটি আদিম মানুষের স্ট্রিম বিশেষীকরণ থাকলে তা কী হবে? একটি বিপর্যয়? :-)
স্টুয়ার্ট

উত্তর:


217

অন্যরা যেমন ইতিমধ্যে উল্লেখ করেছে, এর পিছনে নকশার সিদ্ধান্তটি ছিল পদ্ধতি এবং শ্রেণীর বিস্ফোরণ রোধ করা।

তবুও, ব্যক্তিগতভাবে আমি মনে করি এটি একটি খুব খারাপ সিদ্ধান্ত ছিল, এবং তাদের উচিত না দেওয়া উচিত CharStream, যা যুক্তিসঙ্গত, পরিবর্তে বিভিন্ন পদ্ধতি না করে chars(), আমি ভেবে দেখব:

  • Stream<Character> chars(), এটি বাক্স অক্ষরগুলির একটি স্ট্রিম সরবরাহ করে, এতে কিছু হালকা পারফরম্যান্স পেনাল্টি থাকবে।
  • IntStream unboxedChars(), যা পারফরম্যান্স কোডের জন্য ব্যবহৃত হবে।

তবে কেন তার দিকে নজর দেওয়ার পরিবর্তে বর্তমানে এটি এইভাবে করা হচ্ছে তা , আমি মনে করি যে এই জবাবটি জাভা 8 এর সাথে আমরা যে এপিআই পেয়েছি তা দিয়ে এটি করার কোনও উপায় দেখানোতে ফোকাস করা উচিত।

জাভা 7 এ আমি এটি এটি করতাম:

for (int i = 0; i < hello.length(); i++) {
    System.out.println(hello.charAt(i));
}

এবং আমি মনে করি জাভা 8 এ এটি করার একটি যুক্তিসঙ্গত পদ্ধতি নিম্নলিখিত:

hello.chars()
        .mapToObj(i -> (char)i)
        .forEach(System.out::println);

এখানে আমি একটি পেয়েছি IntStreamএবং ল্যাম্বদার মাধ্যমে এটি কোনও বস্তুতে ম্যাপ i -> (char)iকরব, এটি এটি স্বয়ংক্রিয়ভাবে এটিকে একটিতে বক্স করবেStream<Character> এবং তারপরে আমরা যা চাই তা করতে পারি, এবং এখনও পদ্ধতি রেফারেন্সকে একটি প্লাস হিসাবে ব্যবহার করি।

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

জাভা 8 এর জন্য অন্যান্য কুরুচিপূর্ণ বিকল্প:

একটিতে থাকা এবং IntStreamচূড়ান্তভাবে সেগুলি মুদ্রণ করতে ইচ্ছুক হয়ে আপনি মুদ্রণের জন্য কোনও পদ্ধতি রেফারেন্স ব্যবহার করতে পারবেন না:

hello.chars()
        .forEach(i -> System.out.println((char)i));

তদুপরি, আপনার নিজস্ব পদ্ধতিতে পদ্ধতির রেফারেন্স ব্যবহার করে আর কাজ হয় না! নিম্নোক্ত বিবেচনা কর:

private void print(char c) {
    System.out.println(c);
}

এবং তারপর

hello.chars()
        .forEach(this::print);

এটি একটি সংকলন ত্রুটি দেবে, কারণ সম্ভবত একটি ক্ষতিকারক রূপান্তর রয়েছে।

উপসংহার:

এপিআই কারণ যোগ করার জন্য অনুপস্থিত না এই পদ্ধতি পরিকল্পনা করা হয়েছিল CharStream, আমি ব্যক্তিগতভাবে মনে করি যে পদ্ধতি একটি ফিরতি উচিত Stream<Character>, এবং কার্যসংক্রান্ত বর্তমানে ব্যবহার করা mapToObj(i -> (char)i)একটি অন IntStreamতাঁদের সঙ্গে ঠিকমত কাজ পাবে।


7
আমার উপসংহার: API এর এই অংশটি ডিজাইনের মাধ্যমে ভেঙে গেছে। তবে বিস্তৃত উত্তরের জন্য ধন্যবাদ
অ্যাডাম ডায়গা

27
+1, তবে আমার প্রস্তাবটি এর codePoints()পরিবর্তে ব্যবহার করা chars()এবং আপনি ইতিমধ্যে intকোড পয়েন্টের জন্য ইতিমধ্যে প্রচুর গ্রন্থাগার ফাংশনগুলি দেখতে পাবেন char, যেমন সমস্ত পদ্ধতির java.lang.Characterপাশাপাশি পদ্ধতি StringBuilder.appendCodePointইত্যাদি This এই সমর্থনটি তখন থেকেই বিদ্যমান jdk1.5
হোলার

6
কোড পয়েন্ট সম্পর্কে ভাল পয়েন্ট। এগুলি ব্যবহার করে পরিপূরক চরিত্রগুলি পরিচালনা করবে, যা একটি Stringবা এর মধ্যে সারোগেট জোড়া হিসাবে উপস্থাপিত হয় char[]। আমি বাজি ধরব যে বেশিরভাগ charপ্রসেসিং কোড সার্ভেট জোড়াকে ভুলভাবে ছড়িয়ে দেয়।
স্টুয়ার্ট

2
@ এসকিউই, সংজ্ঞায়িত করুন void print(int ch) { System.out.println((char)ch); }এবং তারপরে আপনি পদ্ধতির উল্লেখগুলি ব্যবহার করতে পারেন।
স্টুয়ার্ট

2
কেন Stream<Character>প্রত্যাখ্যান করা হয়েছিল তার জন্য আমার উত্তর দেখুন ।
স্টুয়ার্ট

90

Skiwi থেকে উত্তর ইতিমধ্যে প্রধান পয়েন্ট অনেক আচ্ছাদিত। আমি আরও কিছুটা পটভূমি পূরণ করব।

যে কোনও এপিআইয়ের ডিজাইন হ'ল ট্রেড অফসের একটি সিরিজ। জাভাতে, একটি জটিল সমস্যা হ'ল অনেক আগে থেকেই তৈরি নকশার সিদ্ধান্ত নিয়ে কাজ করা।

প্রিমিটিভগুলি জাভাতে রয়েছে 1.0 থেকে since তারা জাভাটিকে একটি "অপরিষ্কার" অবজেক্ট-ভিত্তিক ভাষা বানায়, যেহেতু আদিম বস্তু নয়। আমি বিশ্বাস করি, বস্তু-ভিত্তিক বিশুদ্ধতার ব্যয়ে কর্মক্ষমতা উন্নত করার এক প্রাকৃতিক সিদ্ধান্ত ছিল believe

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

স্ট্রিমস এপিআই ডিজাইন করার সময় এটি স্পষ্ট ছিল যে আমাদের আদিমদের সমর্থন করতে হয়েছিল। বক্সিং / আনবক্সিং ওভারহেড সমান্তরালতা থেকে কোনও কার্যকারিতা সুবিধা হারাতে পারে। আমরা সমস্ত আদিম মানুষকে সমর্থন করতে চাইনি , যদিও এপিআইতে বিপুল পরিমাণে বিশৃঙ্খলা যুক্ত হত। (আপনি কি সত্যই এর ব্যবহার দেখতে পাচ্ছেন ShortStream?) "সমস্ত" বা "কোনওটিই" ডিজাইনের জন্য আরামদায়ক জায়গা, তবুও উভয়ই গ্রহণযোগ্য ছিল না। সুতরাং আমাদের "কিছু" এর একটি যুক্তিসঙ্গত মান খুঁজে পেতে হয়েছিল। আমরা আদিম বিশেষায়িত সঙ্গে শেষ পর্যন্ত int, longএবং double। (ব্যক্তিগতভাবে আমি বাদ পড়তে পারতাম intতবে এটি কেবল আমি।)

যেহেতু CharSequence.chars()আমরা প্রত্যাবর্তন বিবেচনা করেছি Stream<Character>(প্রথম দিকে প্রোটোটাইপ এটি প্রয়োগ করতে পারে) তবে বক্সিং ওভারহেডের কারণে এটি প্রত্যাখ্যান করা হয়েছিল। একটি স্ট্রিং রয়েছে তা বিবেচনা করেcharস্ট্রিংয়ের আদিম হিসাবে মান করে, কলারটি শর্তহীনভাবে বক্সিং চাপিয়ে দেওয়া ভুল বলে মনে হবে যখন কলার সম্ভবত কেবলমাত্র মানটির উপর কিছুটা প্রসেসিং করবে এবং এটি ডানদিকে ফিরিয়ে আনবে।

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

কলকারীদের উপর এই শাস্তি চাপিয়ে দেয় তা হ'ল তাদের জানতে হবে যে উপস্থাপিত হিসাবে মানগুলি IntStreamরয়েছে এবং কাস্টিং অবশ্যই যথাযথ জায়গায় করা উচিত। এটি দ্বিগুণ বিভ্রান্তিকর কারণ এখানে ওভারলোড হওয়া এপিআই কলগুলি রয়েছে এবং এটি তাদের আচরণে স্পষ্টতই পৃথক। বিভ্রান্তির একটি অতিরিক্ত পয়েন্ট সম্ভবত উত্থাপিত হয়েছে কারণ কলটি একটি ফেরত দেয় তবে এতে থাকা মানগুলি একেবারেই আলাদা।charintsPrintStream.print(char)PrintStream.print(int)codePoints()IntStream

সুতরাং, বেশ কয়েকটি বিকল্পের মধ্যে এটি ব্যবহারিকভাবে বেছে নেওয়ার জন্য উত্সাহিত হয়:

  1. আমরা কোনও আদিম বিশেষত্ব সরবরাহ করতে পারি না, যার ফলে একটি সাধারণ, মার্জিত, ধারাবাহিক এপিআই হয়, তবে এটি একটি উচ্চ কার্যকারিতা এবং জিসি ওভারহেড চাপিয়ে দেয়;

  2. আমরা জেডিকে বিকাশকারীদের উপর রক্ষণাবেক্ষণের বোঝা চাপিয়ে, এপিআই খাড়া করার ব্যয়ে, আদিম বিশেষজ্ঞের একটি সম্পূর্ণ সেট সরবরাহ করতে পারি; অথবা

  3. আমরা একটি মাঝারি আকারের, উচ্চ সম্পাদনকারী এপিআই প্রদান করে যে আঞ্চলিক আকারের সংক্ষিপ্ত ব্যবহারের ক্ষেত্রে (চর প্রক্রিয়াজাতকরণ) কলকারীদের উপর তুলনামূলকভাবে ছোট বোঝা চাপিয়ে আদিম বিশেষত্বের একটি উপসেট সরবরাহ করতে পারি।

আমরা শেষটি বেছে নিয়েছি।


1
চমৎকার উত্তর! তবে এটির উত্তর নেই কেন কেন দুটি ভিন্ন পদ্ধতি থাকতে পারে না chars(), একটি যা Stream<Character>(ছোট পারফরম্যান্সের জরিমানা সহ) প্রদান করে এবং অন্যটি IntStream, এটিও বিবেচনা করা হয়েছিল? Stream<Character>পারফরম্যান্স পেনাল্টির তুলনায় যদি বিশ্বাসযোগ্যতা এটির জন্য উপযুক্ত বলে মনে হয় তবে লোকেরা যে কোনও উপায়ে এটির ম্যাপিং শেষ করবে এটি সম্ভবত যথেষ্ট is
স্কিভি

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

5
সদৃশ প্রশ্নের জন্য ধন্যবাদ আমি এটি একটি লক্ষ্য করেছি। আমি সম্মত হই যে এই পদ্ধতিটি খুব কমই ব্যবহৃত হয়, বিশেষত এই বিষয়টি প্রদত্ত যে chars()ফিরিয়ে IntStreamদেওয়া বড় সমস্যা নয়। তবে এটি একটি বিল্ট-ইন ভাবে ফিরে রূপান্তর আছে ভাল হবে IntStreamথেকে String। এটি দিয়ে করা যেতে পারে .reduce(StringBuilder::new, (sb, c) -> sb.append((char)c), StringBuilder::append).toString(), তবে এটি সত্যই দীর্ঘ।
তাগীর ভালিভ

7
@ তাগিরওয়ালিভ হ্যাঁ এটি কিছুটা জটিল। কোড পয়েন্ট একটি স্ট্রিম সঙ্গে (একটি IntStream) তা না খুব খারাপ হল: collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString()। আমার ধারণা এটি সত্যিই খাটো নয়, তবে কোড পয়েন্টগুলি ব্যবহার করা (char)কাস্টগুলি এড়িয়ে যায় এবং পদ্ধতি রেফারেন্সগুলি ব্যবহারের অনুমতি দেয়। এছাড়াও এটি surrogates সঠিকভাবে পরিচালনা করে।
স্টুয়ার্ট

2
@ ইলিয়াবাইস্ট্রভ দুর্ভাগ্যক্রমে আদিম ধারাগুলি যেমন IntStreamকোনও collect()পদ্ধতি গ্রহণ করে না Collectorcollect()পূর্ববর্তী মন্তব্যে উল্লিখিত তাদের কাছে কেবল তিন-আর্গ পদ্ধতি রয়েছে।
স্টুয়ার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.