জাভা 9 এ স্ট্রিং কনটেনটেশন কীভাবে প্রয়োগ করা হয়?


111

JEP 280 তে লেখা আছে : স্ট্রিং কনক্যাটেনেশন নির্দেশ করুন :

Stringজেডিকে লাইব্রেরি ফাংশনে কলগুলি javacব্যবহার invokedynamicকরার জন্য উত্পন্ন স্ট্যাটিক- কনটেনটেশন বাইটকোড ক্রম পরিবর্তন করুন । এটি Stringদ্বারা প্রেরিত বাইটকোডে আরও পরিবর্তনের প্রয়োজন ছাড়াই ভবিষ্যতের সংমিশ্রনের অপ্টিমাইজেশানগুলি সক্ষম করবে javac

এখানে আমি বুঝতে চাই যে invokedynamicকলগুলির ব্যবহার কী এবং বাইটকোড উপসংহার থেকে invokedynamicকীভাবে আলাদা ?


11
আমি এই সম্পর্কে কিছুক্ষণ আগে লিখেছিলাম - এটি যদি সহায়তা করে তবে আমি এটিকে একটি উত্তরে সরিয়ে দেব।
নিকোলাই

10
এছাড়াও, এই ভিডিওটিতে একবার নজর দিন যা নতুন স্ট্রিং
কনক্রিটেশন

3
@ Kaেকা কোজলোভ আমি আশা করি যে আমি আপনার মন্তব্যে দুবার ভোট দিতে পারব, এই সমস্ত বাস্তবায়নকারীদের কাছ থেকে আসা লিঙ্কগুলি সর্বোত্তম।
ইউজিন

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

উত্তর:


95

"পুরানো" উপায় আউটপুট StringBuilderএকমুখী - ওরিয়েন্টেড ক্রিয়াকলাপ। এই প্রোগ্রামটি বিবেচনা করুন:

public class Example {
    public static void main(String[] args)
    {
        String result = args[0] + "-" + args[1] + "-" + args[2];
        System.out.println(result);
    }
}

যদি আমরা জেডিকে ৮ বা তার আগের সংকলন করি এবং তারপরে javap -c Exampleবাইটকোড দেখতে ব্যবহার করি, আমরা এরকম কিছু দেখতে পাই:

পাবলিক ক্লাস উদাহরণ {
  সর্বজনীন উদাহরণ ();
    কোড:
       0: aload_0
       1: ইনভোকেসপেশিয়াল # 1 // পদ্ধতি জাভা / ল্যাং / অবজেক্ট "" <init> ":() ভি
       4: ফিরে

  পাবলিক স্ট্যাটিক শূন্য মূল (java.lang.String []);
    কোড:
       0: নতুন # 2 // শ্রেণি জাভা / ল্যাং / স্ট্রিংবিল্ডার
       3: ডুপ
       4: ইনভোকেসপেশিয়াল # 3 // পদ্ধতি জাভা / ল্যাং / স্ট্রিংবিল্ডার "" <init> ":() ভি
       7: aload_0
       8: আইকনস্ট_0
       9: অ্যালাড
      10: invokevirtual # 4 // পদ্ধতি java / lang / StringBuilder.append: (লাজাভা / ল্যাং / স্ট্রিং;) লাজাভা / ল্যাং / স্ট্রিংবিল্ডার;
      13: ldc # 5 // স্ট্রিং -
      15: invokevirtual # 4 // পদ্ধতি java / lang / StringBuilder.append: (লাজাভা / ল্যাং / স্ট্রিং;) লাজাভা / ল্যাং / স্ট্রিংবিল্ডার;
      18: aload_0
      19: আইকনস্ট_1
      20: অ্যালাড
      21: invokevirtual # 4 // পদ্ধতি java / lang / StringBuilder.append: (লাজাভা / ল্যাং / স্ট্রিং;) লাজাভা / ল্যাং / স্ট্রিংবিল্ডার;
      24: ldc # 5 // স্ট্রিং -
      26: invokevirtual # 4 // পদ্ধতি java / lang / StringBuilder.append: (লাজাভা / ল্যাং / স্ট্রিং;) লাজাভা / ল্যাং / স্ট্রিংবিল্ডার;
      29: aload_0
      30: আইকনস্ট_2
      31: অ্যালাড
      32: invokevirtual # 4 // পদ্ধতি java / lang / StringBuilder.append: (লাজাভা / ল্যাং / স্ট্রিং;) লাজাভা / ল্যাং / স্ট্রিংবিল্ডার;
      35: invokevirtual # 6 // পদ্ধতি জাভা / ল্যাং / স্ট্রিংবিল্ডার.টো স্ট্রিং :() লাজাভা / ল্যাং / স্ট্রিং;
      38: অ্যাস্টোর_1
      39: গেসট্যাটিক # 7 // ফিল্ড জাভা / ল্যাং / সিস্টেম.আউট: লাজাভা / আইও / মুদ্রণপ্রবাহ;
      42: aload_1
      43: invokevirtual # 8 // পদ্ধতি জাভা / io / মুদ্রণপ্রবাহ.প্রিন্টলন: (লাজভা / ল্যাং / স্ট্রিং;) ভি
      46: ফিরে
}

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

জাভা 9 কী উত্পন্ন করে তা দেখুন:

পাবলিক ক্লাস উদাহরণ {
  সর্বজনীন উদাহরণ ();
    কোড:
       0: aload_0
       1: ইনভোকেসপেশিয়াল # 1 // পদ্ধতি জাভা / ল্যাং / অবজেক্ট "" <init> ":() ভি
       4: ফিরে

  পাবলিক স্ট্যাটিক শূন্য মূল (java.lang.String []);
    কোড:
       0: aload_0
       1: আইকনস্টটায়
       2: অ্যালাড
       3: aload_0
       4: আইকনস্ট_1
       5: অ্যালোয়াড
       6: aload_0
       7: আইকনস্ট_2
       8: অ্যালাড
       9: ইনভোকাডাইনামিক # 2, 0 // ইনভোকডাইনামিক # 0: #ConcatWithConstants: (লাজাভা / ল্যাং / স্ট্রিং; লাজভা / ল্যাং / স্ট্রিং; লাজাভা / ল্যাং / স্ট্রিং;) লাজাভা / ল্যাং / স্ট্রিং;
      14: অ্যাস্টোর_1
      15: গেসট্যাটিক # 3 // ফিল্ড জাভা / ল্যাং / সিস্টেম.আউট: লাজাভা / আইও / মুদ্রণপ্রবাহ;
      18: এলোড_1
      19: উদ্দীপনা # 4 // পদ্ধতি জাভা / আইও / মুদ্রণপ্রবাহ.প্রিন্টলন: (লাজভা / ল্যাং / স্ট্রিং;) ভি
      22: ফিরে
}

ওহ আমার তবে এটাই খাটো। :-) এটি makeConcatWithConstantsথেকে একটি কল আসে StringConcatFactory, যা এটি তার জাভাদকে বলে:

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


41
এটি আমাকে প্রায় 6 বছর আগে লিখেছিল এমন একটি উত্তরের কথা মনে করিয়ে দেয়: stackoverflow.com/a/7586780/330057 - কেউ জিজ্ঞাসা করেছে তাদের স্ট্রিংবিল্ডার করা উচিত বা +=লুপের জন্য কেবল তাদের সরল পুরানো ব্যবহার করা উচিত । আমি তাদের বলেছি এটি নির্ভরশীল, তবে আসুন ভুলে যাবেন না যে তারা রাস্তার নিচে কোনও সময় কনক্যাট স্ট্রিংয়ের আরও ভাল উপায় খুঁজে পেতে পারে। মূল লাইনটি সত্যই পেনাল্টিমেট লাইন:So by being smart, you have caused a performance hit when Java got smarter than you.
কর্সিকা

3
@ করসিকা: লোল! তবে বাহ, সেখানে পৌঁছতে দীর্ঘ সময় লেগেছিল (আমার অর্থ ছয় বছর নয়, আমি 22 বা তার মানে ... :-))
টিজে ক্রোডার

1
@ সুপের্যাট: আমি যেমন বুঝতে পেরেছি, এর বেশ কয়েকটি কারণ রয়েছে, কম-বেশি নয় যে পারফরম্যান্স-সমালোচনামূলক পথে কোনও পদ্ধতিতে পাস করার জন্য একটি ভারার্গস অ্যারে তৈরি করা আদর্শ নয়। এছাড়াও, ব্যবহারের invokedynamicমাধ্যমে রানটাইমের সময় বিভিন্ন অনুরোধ কৌশল বেছে নেওয়া এবং প্রতিটি অনুরোধে কোনও মেথড কল এবং প্রেরণ টেবিলের ওভারহেড ছাড়াই প্রথম অনুরোধে আবদ্ধ হতে দেওয়া হয়; আরও Nicolai এর নিবন্ধ এখানে এবং JEP
টিজে ক্রাউডার

1
@ সুপের্যাট: এবং তারপরে এই সত্য আছে যে এটি স্ট্রিং-নন-স্ট্রিংয়ের সাথে ভাল খেলবে না, কারণ তারা চূড়ান্ত ফলাফলে রূপান্তরিত হওয়ার পরিবর্তে স্ট্রিংয়ে প্রাক রূপান্তরিত হতে হবে; আরও অদক্ষতা এটি তৈরি Objectকরতে পারত, তবে তারপরে আপনাকে সমস্ত আদিম বাক্স তৈরি করতে হবে ... (যা নিকোলাই তার চমৎকার নিবন্ধটি বিটিডব্লিউতে অন্তর্ভুক্ত করেছে)
টিজে ক্রোডার

2
@ সুপের্যাট আমি ইতিমধ্যে বিদ্যমান String.concat(String)পদ্ধতিটির উল্লেখ করছিলাম যার বাস্তবায়ন ফলস্বরূপ স্ট্রিংয়ের অ্যারেটি জায়গায় তৈরি করছে। আমাদের যখন toString()স্বেচ্ছাচারিত বস্তুগুলিতে প্রার্থনা করতে হয় তখন সুবিধাটি ততক্ষণ হয়ে যায় । তেমনি, অ্যারে গ্রহণ করার পদ্ধতিটি কল করার সময়, কলারকে অ্যারে তৈরি করতে হবে এবং পূরণ করতে হবে যা সামগ্রিক সুবিধা হ্রাস করে। তবে এখন এটি অপ্রাসঙ্গিক, কারণ নতুন সমাধানটি মূলত আপনি যা বিবেচনা করছেন তা ব্যতীত এর কোনও বক্সিং ওভারহেড নেই, কোনও অ্যারে তৈরির প্রয়োজন নেই, এবং ব্যাকএন্ড নির্দিষ্ট পরিস্থিতির জন্য অনুকূলিত হ্যান্ডলার তৈরি করতে পারে।
হলগার

20

invokedynamicআমার কথায় স্ট্রিং কনটেনটেশনের অপ্টিমাইজেশনের জন্য ব্যবহৃত বাস্তবায়নের বিশদটি যাওয়ার আগে , আমার কী প্রয়োজন তা কীভাবে ব্যবহার করা যায় এবং কীভাবে এটি ব্যবহার করব?

invokedynamic নির্দেশ সরলীকৃত এবং সম্ভাব্য কম্পাইলার এবং জেভিএম উপর গতিশীল ভাষার জন্য রানটাইম ব্যবস্থা বাস্তবায়নের উন্নত । এটি ভাষা প্রয়োগকারীকে invokedynamicনীচের পদক্ষেপগুলির সাথে নির্দেশাবলীর সাথে কাস্টম লিঙ্কেজ আচরণ সংজ্ঞায়িত করার অনুমতি দিয়ে এটি করে ।


আমি সম্ভবত চেষ্টা করব এবং স্ট্রিং কনটেনটেশন অপ্টিমাইজেশান বাস্তবায়নের জন্য যে পরিবর্তন আনা হয়েছিল সেগুলি দিয়ে আপনাকে এটি দিয়ে নিয়ে যেতে চাই।

  • বুটস্ট্র্যাপ পদ্ধতিটি সংজ্ঞায়িত : - জাভা 9 এর সাথে, প্রাথমিকভাবে স্ট্রিং কনটেন্টেশন সমর্থন করার জন্য invokedynamicকল সাইটগুলির জন্য বুটস্ট্র্যাপ পদ্ধতিগুলি এবং প্রয়োগের সাথে পরিচয় করানো হয়েছিল makeConcatmakeConcatWithConstantsStringConcatFactory

    ইনভয়েডিনামিকের ব্যবহার রানটাইম পর্যন্ত অনুবাদ কৌশল নির্বাচন করার বিকল্প সরবরাহ করে। ব্যবহৃত অনুবাদ কৌশলটি পূর্ববর্তী জাভা সংস্করণে প্রবর্তিত StringConcatFactoryমতোই to LambdaMetafactoryঅতিরিক্তভাবে প্রশ্নে উল্লিখিত জেইপির অন্যতম লক্ষ্য হ'ল এই কৌশলগুলি আরও প্রসারিত করা।

  • কনস্ট্যান্ট পুলের এন্ট্রিগুলি নির্দিষ্ট করে : - invokedynamicনির্দেশাবলীর (1) MethodHandles.Lookupঅবজেক্টের বাইরে নির্দেশের অতিরিক্ত স্ট্যাটিক আর্গুমেন্ট যা invokedynamicনির্দেশের প্রসঙ্গে হ্যান্ডলগুলি তৈরি করার জন্য একটি কারখানা , (2) একটি Stringবস্তু, গতিশীল কলটিতে উল্লিখিত পদ্ধতির নাম সাইট এবং (3) MethodTypeঅবজেক্ট, গতিশীল কল সাইটের সমাধানের ধরণের স্বাক্ষর।

    কোডের লিঙ্কেজের সময় ইতিমধ্যে সংযুক্ত রয়েছে। রানটাইম এ, বুটস্ট্র্যাপ পদ্ধতিটি চালিত হয় এবং সংক্ষিপ্তকরণটি করে আসল কোডে লিঙ্কগুলি। এটি invokedynamicএকটি উপযুক্ত invokestaticকল দিয়ে কলটি পুনরায় লিখন করে । এটি ধ্রুবক পুল থেকে ধ্রুবক স্ট্রিং লোড করে, বুটস্ট্র্যাপ পদ্ধতি স্ট্যাটিক আরোগুলি এগুলি এবং অন্যান্য ধ্রুবককে সরাসরি বুটস্ট্র্যাপ পদ্ধতি কলটিতে পাস করার জন্য ব্যবহার করা হয়।

  • ইনভয়েডিনামিক নির্দেশাবলী ব্যবহার করে : - এটি প্রাথমিক আহবানকালে একবার কল টার্গেটকে বুটস্ট্র্যাপ করার মাধ্যম সরবরাহ করে একটি অলস সংযোগের জন্য সুবিধাগুলি সরবরাহ করে। এখানে অপ্টিমাইজেশনের জন্য কংক্রিট ধারণাটি হ'ল StringBuilder.appendএকটি সাধারণ invokedynamicকল দিয়ে পুরো নৃত্যকে প্রতিস্থাপন করা java.lang.invoke.StringConcatFactory, যা সংক্ষিপ্তকরণের প্রয়োজনীয়তার মানগুলি গ্রহণ করবে।

Indify স্ট্রিং সংযুক্তকরণের একটি উদাহরণ দিয়ে প্রস্তাব রাজ্যের যেখানে যেমন দ্বারা ভাগ করা একটি অনুরূপ পদ্ধতি Java9 সাথে সংশ্লিষ্ট অ্যাপ্লিকেশনের মাপকাঠিতে @TJ Crowder কম্পাইল করা হয় এবং বাইটকোড পার্থক্য মোটামুটি নানারকম বাস্তবায়ন মধ্যে দৃশ্যমান হয়।


17

আমি এখানে কিছুটা বিশদ যুক্ত করব। মূল অংশটি হ'ল স্ট্রিং কনটেন্টেশন কীভাবে করা হয় তা রানটাইম সিদ্ধান্ত, আর কোনও সংকলনের সময় নয় । সুতরাং এটি পরিবর্তিত হতে পারে যার অর্থ আপনি জাভা -9 এর বিপরীতে একবার আপনার কোডটি সংকলন করেছেন এবং এটি অন্তর্নিহিত বাস্তবায়নটি পরিবর্তন করতে পারে তবে এটি খুশি হয়, পুনরায় সংকলনের প্রয়োজন ছাড়াই।

এবং দ্বিতীয় বিষয়টি এই মুহুর্তে রয়েছে 6 possible strategies for concatenation of String:

 private enum Strategy {
    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder}.
     */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
    BC_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also tries to estimate the required storage.
     */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
    MH_INLINE_SIZED_EXACT
}

আপনি একটি প্যারামিটার মাধ্যমে তাদের কোন একটি নির্বাচন করুন: -Djava.lang.invoke.stringConcat। লক্ষ্য করুন যে StringBuilderএখনও একটি বিকল্প।

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