জাভাতে টু স্ট্রিং () এ স্ট্রিংবিল্ডার বনাম স্ট্রিং সংমিশ্রণ


925

toString()নীচে দুটি বাস্তবায়ন দেওয়া , কোনটি পছন্দ:

public String toString(){
    return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}

অথবা

public String toString(){
    StringBuilder sb = new StringBuilder(100);
    return sb.append("{a:").append(a)
          .append(", b:").append(b)
          .append(", c:").append(c)
          .append("}")
          .toString();
}

?

আরও গুরুত্বপূর্ণ, আমাদের কেবলমাত্র 3 টি বৈশিষ্ট্য দেওয়া থাকলে এটি কোনও তাত্পর্যপূর্ণ হতে পারে না, তবে আপনি কোন বিন্দুতে +কনক্যাট থেকে স্যুইচ করবেন StringBuilder?


40
আপনি কোন স্থানে স্ট্রিংবিল্ডারে স্যুইচ করেন? যখন এটি মেমরি বা কর্মক্ষমতা প্রভাবিত করে। বা যখন এটি হতে পারে। আপনি যদি সত্যিই কেবল একবারে কয়েকটি স্ট্রিংয়ের জন্য এটি করছেন তবে কোনও উদ্বেগ নেই। আপনি যদি বার বার এটি করতে যাচ্ছেন তবে স্ট্রিংবিল্ডার ব্যবহার করার সময় আপনার একটি পরিমাপযোগ্য পার্থক্য দেখা উচিত।
ewall

প্যারামিটারে 100 এর অর্থ কী?
আসিফ মোশতাক

2
@ অজ্ঞাত 100 হ'ল স্ট্রিংবিল্ডারের প্রাথমিক আকার
নন

@ অনসকিউটার তাই সর্বোচ্চ অক্ষর 100 হবে?
আসিফ মোশতাক

10
@ কেবলমাত্র প্রাথমিক মাপের অজানা, আপনি যে স্ট্রিংয়ের সাথে লেনদেন করছেন তার আনুমানিক আকারটি যদি জানেন তবে আপনি StringBuilderকী পরিমাণ আকারকে সামনে বরাদ্দ করতে পারবেন তা জানাতে পারেন অন্যথায় এটি যদি স্থানের বাইরে চলে যায় তবে একটি আকার তৈরি করে আকার দ্বিগুণ করতে হবে নতুন char[]অ্যারে তারপরে ডেটা অনুলিপি করুন - যা ব্যয়বহুল। আপনি আকারটি দিয়ে প্রতারণা করতে পারেন এবং তারপরে এই অ্যারে তৈরির কোনও প্রয়োজন নেই - সুতরাং আপনি যদি মনে করেন যে আপনার স্ট্রিংটি ~ 100 অক্ষর দীর্ঘ হবে তবে আপনি স্ট্রিংবিল্ডারটিকে সেই আকারটিতে সেট করতে পারেন এবং এটি কখনও অভ্যন্তরীণভাবে প্রসারিত করতে হবে না।
নন সিকুইটার

উত্তর:


964

সংস্করণ 1 পছন্দনীয় কারণ এটি সংক্ষিপ্ত এবং সংকলক আসলে এটি 2 সংস্করণে রূপান্তরিত করবে - কোনও পারফরম্যান্সের পার্থক্য নেই।

আরও গুরুত্বপূর্ণভাবে আমাদের দেওয়া মাত্র 3 টি বৈশিষ্ট্য এটির কোনও পার্থক্য নাও হতে পারে তবে আপনি কোন সময়ে কনক্যাট থেকে বিল্ডারে স্যুইচ করবেন?

আপনি যখন একটি লুপে সংযোগ দিচ্ছেন সেই মুহুর্তে - সাধারণত যখন সংকলকটি নিজের StringBuilderদ্বারা প্রতিস্থাপন করতে না পারে।


19
এটি সত্য তবে ভাষার রেফারেন্সও বলেছে যে এটি alচ্ছিক। আসলে, আমি জেআরই 1.6.0_15 এর সাথে একটি সাধারণ পরীক্ষা করেছি এবং পচনশীল শ্রেণিতে কোনও সংকলক অপ্টিমাইজেশন দেখিনি।
bruno conde

37
আমি কেবল প্রশ্নটি থেকে কোডটি চেষ্টা করেছি (জেডিকে 1.6.0_16 তে সংকলিত) এবং প্রত্যাশা অনুযায়ী অপ্টিমাইজেশনটি পেয়েছি। আমি নিশ্চিত যে সমস্ত আধুনিক সংকলকরা এটি করবে।
মাইকেল বর্গওয়ার্ট 16

22
আপনি সঠিক. বাইকোডের দিকে তাকিয়ে আমি স্পষ্টভাবে স্ট্রিংবিল্ডার অপ্টিমাইজেশন দেখতে পাচ্ছি। আমি একটি ডিকম্পিলার ব্যবহার করছিলাম এবং এটি কিছুটা আবার কনকটে রূপান্তর করছে। +1
bruno conde

80
একটি মৃত ঘোড়াটি মারতে নয়, তবে অনুমানের শব্দটি হ'ল: To increase the performance of repeated string concatenation, a Java compiler _may_ use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.মূল শব্দটি সেখানে থাকতে পারে । প্রদত্ত যে এটি সরকারীভাবে isচ্ছিক (যদিও সম্ভবত বাস্তবায়িত হয়) আমাদের কী নিজেকে রক্ষা করা উচিত নয়?
লুকাস

93
@ লুকাস: না, আমাদের করা উচিত নয়। সংকলক যদি সেই অপ্টিমাইজেশনটি সম্পাদন না করার সিদ্ধান্ত নেয়, তবে এটির পক্ষে এটি উপযুক্ত নয়। 99% ক্ষেত্রে, সংকলকটি আরও ভাল করে জানে যে কোনটি অপ্টিমাইজেশনের জন্য এটি উপযুক্ত so সুতরাং থাম্বের নিয়ম হিসাবে দেবকে হস্তক্ষেপ করা উচিত নয়। অবশ্যই, আপনার পরিস্থিতি অন্যান্য 1% এর মধ্যে পড়তে পারে তবে এটি কেবল (সতর্কতার সাথে) বেঞ্চমার্কিং দ্বারা পরীক্ষা করা যেতে পারে।

255

মূলটি হ'ল আপনি এক জায়গায় সমস্ত যুক্তি লিখছেন বা সময়ের সাথে সাথে এটি জমা করছেন।

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

তবে আপনি যদি একটি লুপের মধ্যে যেমন একটি স্ট্রিং তৈরি করে থাকেন তবে স্ট্রিংবিল্ডার ব্যবহার করুন।

স্পষ্ট করার জন্য, ধরে নিলাম যে বিশালাকারে হাজার হাজার স্ট্রিং রয়েছে, এর মতো কোড:

...
String result = "";
for (String s : hugeArray) {
    result = result + s;
}

তুলনায় খুব সময়- এবং স্মৃতি-অপব্যয়:

...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
    sb.append(s);
}
String result = sb.toString();

3
হ্যাঁ, স্ট্রিংবিল্ডারকে স্ট্রিং অবজেক্টটি বারবার তৈরি করার দরকার নেই।
ওলগা

124
ড্যাম্মিট আমি সেই 2 টি ফাংশনটি ব্যবহার করেছি একটি বড় স্ট্রিং যা আমি কাজ করছি তা পরীক্ষা করার জন্য 6.৫১ মিনিট বনাম ১১ সেকস
ব্যবহারকারী 1722791

1
উপায় দ্বারা আপনি result += s;পাশাপাশি ব্যবহার করতে পারেন (প্রথম উদাহরণে)
RAnders00

1
এই বিবৃতি দ্বারা কতটি অবজেক্ট তৈরি হবে? "{a:"+ a + ", b:" + b + ", c: " + c +"}";
আসিফ মোশতাক

1
স্ট্রিং স্ট্রিং = (a == নাল) এর মতো কি সম্পর্কে? নাল: এ '+ (খ == নাল)? নাল: বি '+ (সি == নাল)? সি: সি '+ ...; ? এটি কি অপ্টিমাইজেশন ঘটতে বাধা দেবে?
amitfr

75

আমি পছন্দ করি:

String.format( "{a: %s, b: %s, c: %s}", a, b, c );

... কারণ এটি সংক্ষিপ্ত এবং পাঠযোগ্য।

আমি চাই না গতির জন্য এই নিখুত যদি না আপনি একটি খুব উচ্চ পুনরাবৃত্তি গণনা সঙ্গে একটি লুপ ভিতরে এটি ব্যবহার এবং কর্মক্ষমতা পার্থক্য মাপা হয়েছে।

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


64
এটি প্রকৃতপক্ষে দীর্ঘতর, আরও চিহ্ন রয়েছে এবং অনুক্রমের বাইরে একটি পাঠ্য ভেরিয়েবল রয়েছে।
টম হাটিন - :11 ই

4
সুতরাং আপনি কি বলবেন যে এটি অন্য অ্যাপ্রোচগুলির চেয়ে কম পাঠযোগ্য?
স্পর্শকাতর

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

78
(আমার জন্য) পড়া কঠিন বলে মনে হচ্ছে। এখন আমাকে {...} এবং পরামিতিগুলির মধ্যে পিছনে পিছনে স্ক্যান করতে হবে।
স্টিভ কুও

10
আমি এই ফর্মটি পছন্দ করি, কারণ এটি যদি নিরাপদ হয় তবে কোনও একটি প্যারামিটারটি থাকলেnull

74

বেশিরভাগ ক্ষেত্রে, আপনি দুটি পদ্ধতির মধ্যে একটি সত্যিকারের পার্থক্য দেখতে পাবেন না, তবে এটির মতো খারাপ পরিস্থিতি তৈরি করা সহজ:

public class Main
{
    public static void main(String[] args)
    {
        long now = System.currentTimeMillis();
        slow();
        System.out.println("slow elapsed " + (System.currentTimeMillis() - now) + " ms");

        now = System.currentTimeMillis();
        fast();
        System.out.println("fast elapsed " + (System.currentTimeMillis() - now) + " ms");
    }

    private static void fast()
    {
        StringBuilder s = new StringBuilder();
        for(int i=0;i<100000;i++)
            s.append("*");      
    }

    private static void slow()
    {
        String s = "";
        for(int i=0;i<100000;i++)
            s+="*";
    }
}

আউটপুটটি হ'ল:

slow elapsed 11741 ms
fast elapsed 7 ms

সমস্যাটি হ'ল + = স্ট্রিংয়ের সাথে যুক্ত হওয়া একটি নতুন স্ট্রিংকে পুনর্গঠন করে, সুতরাং এটি আপনার স্ট্রিংয়ের দৈর্ঘ্যের (উভয়ের যোগফল) রৈখিক কিছু ব্যয় করে।

সুতরাং - আপনার প্রশ্নের:

দ্বিতীয় পদ্ধতির দ্রুত হবে, তবে এটি কম পাঠযোগ্য এবং বজায় রাখা আরও শক্ত। আমি যেমন বলেছি, আপনার নির্দিষ্ট ক্ষেত্রে আপনি সম্ভবত পার্থক্য দেখতে পাবেন না।


.Ccat () সম্পর্কে ভুলবেন না। মূল পোস্ট উদাহরণের মতো সংক্ষিপ্ত স্ট্রিংগুলি ব্যবহার করার সময় আমি 10 থেকে 18 এমএস পর্যন্ত যে কোনও সময় কাটানোর জন্য সময় অতিবাহিত করব।
দ্রুও

9
আপনি ঠিক +=যখনই ছিলেন, আসল উদাহরণটি এমন একটি ক্রম ছিল +, যেটি সংকলকটি একটি string.concatকলে পরিবর্তিত হয়েছিল । আপনার ফলাফল প্রযোজ্য নয়।
অন্ধ

1
@ ব্লিন্ডি এবং ড্রু: - আপনি উভয়ই ঠিক আছেন such এই জাতীয় দৃশ্যে .ccate ব্যবহার করা সবচেয়ে ভাল কাজ, কারণ + = প্রতিবার লুপের রুটিন সম্পাদন করে নতুন অবজেক্ট তৈরি করে।
পেরিলব্রেন

3
আপনি কি জানেন যে তার টস্ট্রিং () কে লুপে ডাকা হয় না?
ওমরি ইয়াদান

গতি পরীক্ষা করার জন্য আমি এই উদাহরণটি চেষ্টা করেছি। সুতরাং আমার ফলাফলগুলি হ'ল ধীর গতিতে 29672 এমএস; দ্রুত বিচ্ছিন্ন 15 এমএস। সুতরাং উত্তর সুস্পষ্ট। তবে এটি যদি 100 টি পুনরাবৃত্তি হবে - সময় একই - 0 এমএস। যদি 500 পুনরাবৃত্তি হয় - 16 এমএস এবং 0 এমএস। ইত্যাদি।
আর্নেস্তাস গ্রুডিস

28

অ্যাপেনড ব্যবহার করতে হবে বা +। তারা অ্যাপেন্ড ব্যবহার করছে কিনা সে বিষয়ে আমার বসের সাথে আমারও সংঘাত হয়েছিল ((তারা এখনও প্রতিবার একটি নতুন অবজেক্ট তৈরি হওয়ার সময় বলতে পারছে না)। সুতরাং আমি কিছু গবেষণা ও ডি করার চেষ্টা করেছি যদিও আমি মাইকেল বর্গওয়ার্টের ব্যাখ্যাটি পছন্দ করি তবে ভবিষ্যতে কারও সত্যই জানা দরকার কিনা তা কেবল একটি ব্যাখ্যা দেখাতে চেয়েছিলাম।

/**
 *
 * @author Perilbrain
 */
public class Appc {
    public Appc() {
        String x = "no name";
        x += "I have Added a name" + "We May need few more names" + Appc.this;
        x.concat(x);
        // x+=x.toString(); --It creates new StringBuilder object before concatenation so avoid if possible
        //System.out.println(x);
    }

    public void Sb() {
        StringBuilder sbb = new StringBuilder("no name");
        sbb.append("I have Added a name");
        sbb.append("We May need few more names");
        sbb.append(Appc.this);
        sbb.append(sbb.toString());
        // System.out.println(sbb.toString());
    }
}

এবং উপরের শ্রেণীর বিযুক্তি হিসাবে প্রকাশিত হয়

 .method public <init>()V //public Appc()
  .limit stack 2
  .limit locals 2
met001_begin:                                  ; DATA XREF: met001_slot000i
  .line 12
    aload_0 ; met001_slot000
    invokespecial java/lang/Object.<init>()V
  .line 13
    ldc "no name"
    astore_1 ; met001_slot001
  .line 14

met001_7:                                      ; DATA XREF: met001_slot001i
    new java/lang/StringBuilder //1st object of SB
    dup
    invokespecial java/lang/StringBuilder.<init>()V
    aload_1 ; met001_slot001
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    ldc "I have Added a nameWe May need few more names"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    aload_0 ; met001_slot000
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
    invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
    astore_1 ; met001_slot001
  .line 15
    aload_1 ; met001_slot001
    aload_1 ; met001_slot001
    invokevirtual java/lang/String.concat(Ljava/lang/String;)Ljava/lang/Strin\
g;
    pop
  .line 18
    return //no more SB created
met001_end:                                    ; DATA XREF: met001_slot000i ...

; ===========================================================================

;met001_slot000                                ; DATA XREF: <init>r ...
    .var 0 is this LAppc; from met001_begin to met001_end
;met001_slot001                                ; DATA XREF: <init>+6w ...
    .var 1 is x Ljava/lang/String; from met001_7 to met001_end
  .end method
;44-1=44
; ---------------------------------------------------------------------------


; Segment type: Pure code
  .method public Sb()V //public void Sb
  .limit stack 3
  .limit locals 2
met002_begin:                                  ; DATA XREF: met002_slot000i
  .line 21
    new java/lang/StringBuilder
    dup
    ldc "no name"
    invokespecial java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    astore_1 ; met002_slot001
  .line 22

met002_10:                                     ; DATA XREF: met002_slot001i
    aload_1 ; met002_slot001
    ldc "I have Added a name"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 23
    aload_1 ; met002_slot001
    ldc "We May need few more names"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 24
    aload_1 ; met002_slot001
    aload_0 ; met002_slot000
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
    pop
  .line 25
    aload_1 ; met002_slot001
    aload_1 ; met002_slot001
    invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 28
    return
met002_end:                                    ; DATA XREF: met002_slot000i ...


;met002_slot000                                ; DATA XREF: Sb+25r
    .var 0 is this LAppc; from met002_begin to met002_end
;met002_slot001                                ; DATA XREF: Sb+9w ...
    .var 1 is sbb Ljava/lang/StringBuilder; from met002_10 to met002_end
  .end method
;96-49=48
; ---------------------------------------------------------------------------

উপরের দুটি কোড থেকে আপনি মাইকেল সঠিক দেখতে পাবেন। প্রতিটি ক্ষেত্রে মাত্র একটি এসবি অবজেক্ট তৈরি করা হয়।


27

জাভা ১.৫ থেকে, "+" এবং স্ট্রিংবিল্ডার.অ্যাপেন্ড () সহ সাধারণ এক লাইন সংমিশ্রণটি একই বাইটকোড উত্পন্ন করে।

কোড পাঠযোগ্যতার স্বার্থে, "+" ব্যবহার করুন।

2 ব্যতিক্রম:

  • মাল্টিথ্রেডেড পরিবেশ: স্ট্রিংবফার
  • লুপগুলিতে সংমিশ্রণ: স্ট্রিংবিল্ডার / স্ট্রিংবফার

22

জাভা (1.8) এর সর্বশেষ সংস্করণ ব্যবহার করা বিচ্ছিন্নতা ( javap -c) সংকলক দ্বারা প্রবর্তিত অপ্টিমাইজেশন দেখায়। +পাশাপাশি sb.append()খুব অনুরূপ কোড উত্পন্ন করবে। তবে, আমরা যদি +লুপের জন্য ব্যবহার করি তবে আচরণটি পরীক্ষা করা সার্থক হবে ।

লুপের জন্য + এ ব্যবহার করে স্ট্রিং যুক্ত করা হচ্ছে

জাভা:

public String myCatPlus(String[] vals) {
    String result = "";
    for (String val : vals) {
        result = result + val;
    }
    return result;
}

বাইটকোড :( forলুপ অংশ)

12: iload         5
14: iload         4
16: if_icmpge     51
19: aload_3
20: iload         5
22: aaload
23: astore        6
25: new           #3                  // class java/lang/StringBuilder
28: dup
29: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
32: aload_2
33: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: aload         6
38: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: astore_2
45: iinc          5, 1
48: goto          12

স্ট্রিংবিল্ডার.এপেন্ড ব্যবহার করে স্ট্রিং যুক্ত করা হচ্ছে

জাভা:

public String myCatSb(String[] vals) {
    StringBuilder sb = new StringBuilder();
    for(String val : vals) {
        sb.append(val);
    }
    return sb.toString();
}

বাইটকোডি :( forলুপের উদ্ধৃতি)

17: iload         5
19: iload         4
21: if_icmpge     43
24: aload_3
25: iload         5
27: aaload
28: astore        6
30: aload_2
31: aload         6
33: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: pop
37: iinc          5, 1
40: goto          17
43: aload_2

যদিও কিছুটা স্পষ্টতই পার্থক্য রয়েছে । প্রথম ক্ষেত্রে, যেখানে +ব্যবহৃত হয়েছিল, StringBuilderলুপ পুনরাবৃত্তির জন্য প্রত্যেকের জন্য নতুন তৈরি করা হয় এবং উত্পন্ন ফলাফলটি একটি toString()কল করে (29 থেকে 41 এর মধ্যে) সংরক্ষণ করা হয়। সুতরাং আপনি মধ্যবর্তী স্ট্রিংগুলি তৈরি করছেন যা লুপে +অপারেটর ব্যবহার করার সময় আপনার সত্যিকারের প্রয়োজন হয় না for


1
এটি কি ওরাকল জেডিকে বা ওপেনজেডিকে?
ক্রিস্টোফ রাউসি

12

জাভা 9 এ সংস্করণ 1 দ্রুত হওয়া উচিত কারণ এটি invokedynamicকলটিতে রূপান্তরিত হয়েছে । আরও বিশদ JEP-280 এ পাওয়া যাবে :

ধারণাটি হল পুরো স্ট্রিংবিল্ডার অ্যাপেন্ড ডান্সকে java.lang.invoke.StringConcatF कार্টিতে একটি সাধারণ ইনভোকাডাইনামিক কল দিয়ে প্রতিস্থাপন করা, যা সংক্ষিপ্তকরণের প্রয়োজনীয়তার মানগুলি স্বীকার করবে।


9

পারফরম্যান্সের কারণে, +=( Stringকনটেন্টেশন) এর ব্যবহারকে নিরুৎসাহিত করা হয়। কারণটি হ'ল: জাভা Stringএকটি অপরিবর্তনীয়, প্রতিবার নতুন কনটেন্টেশন করার সময় একটি নতুন Stringতৈরি করা হয় ( স্ট্রিং পুলে ইতিমধ্যে পুরানোটির থেকে নতুনটির আলাদা ফিঙ্গারপ্রিন্ট রয়েছে )। নতুন স্ট্রিং তৈরি করা জিসির উপর চাপ সৃষ্টি করে এবং প্রোগ্রামটি ধীর করে দেয়: অবজেক্ট তৈরি ব্যয়বহুল।

নীচের কোডগুলিকে একই সময়ে আরও ব্যবহারিক এবং স্পষ্ট করা উচিত।

public static void main(String[] args) 
{
    // warming up
    for(int i = 0; i < 100; i++)
        RandomStringUtils.randomAlphanumeric(1024);
    final StringBuilder appender = new StringBuilder();
    for(int i = 0; i < 100; i++)
        appender.append(RandomStringUtils.randomAlphanumeric(i));

    // testing
    for(int i = 1; i <= 10000; i*=10)
        test(i);
}

public static void test(final int howMany) 
{
    List<String> samples = new ArrayList<>(howMany);
    for(int i = 0; i < howMany; i++)
        samples.add(RandomStringUtils.randomAlphabetic(128));

    final StringBuilder builder = new StringBuilder();
    long start = System.nanoTime();
    for(String sample: samples)
        builder.append(sample);
    builder.toString();
    long elapsed = System.nanoTime() - start;
    System.out.printf("builder - %d - elapsed: %dus\n", howMany, elapsed / 1000);

    String accumulator = "";
    start = System.nanoTime();
    for(String sample: samples)
        accumulator += sample;
    elapsed = System.nanoTime() - start;
    System.out.printf("concatenation - %d - elapsed: %dus\n", howMany, elapsed / (int) 1e3);

    start = System.nanoTime();
    String newOne = null;
    for(String sample: samples)
        newOne = new String(sample);
    elapsed = System.nanoTime() - start;
    System.out.printf("creation - %d - elapsed: %dus\n\n", howMany, elapsed / 1000);
}

একটি রান জন্য ফলাফল নীচে রিপোর্ট করা হয়।

builder - 1 - elapsed: 132us
concatenation - 1 - elapsed: 4us
creation - 1 - elapsed: 5us

builder - 10 - elapsed: 9us
concatenation - 10 - elapsed: 26us
creation - 10 - elapsed: 5us

builder - 100 - elapsed: 77us
concatenation - 100 - elapsed: 1669us
creation - 100 - elapsed: 43us

builder - 1000 - elapsed: 511us
concatenation - 1000 - elapsed: 111504us
creation - 1000 - elapsed: 282us

builder - 10000 - elapsed: 3364us 
concatenation - 10000 - elapsed: 5709793us
creation - 10000 - elapsed: 972us

1 টি কনটেনটেশনের ফলাফলগুলি বিবেচনা না করে (জেআইটি এখনও তার কাজটি করে নি), এমনকি 10 টি সম্মেলনের জন্য পারফরম্যান্সের শাস্তি প্রাসঙ্গিক; হাজার হাজার সম্মেলনের জন্য, পার্থক্যটি বিশাল।

এই তাত্ক্ষণিক পরীক্ষা থেকে শিখানো পাঠ (উপরের কোডটি দিয়ে সহজেই পুনরুত্পাদনযোগ্য): +=স্ট্রিংগুলি একসাথে ব্যবহার করতে কখনও কখনও ব্যবহার করবেন না , এমনকি কয়েকটি মৌলিক ক্ষেত্রে যেখানে নতুন কনস্ট্রাকশন প্রয়োজন (যেমন বলা হয়েছে, নতুন স্ট্রিং তৈরি করা যে কোনও উপায়ে ব্যয়বহুল এবং চাপ সৃষ্টি করে) জিসি)।


9

নীচের উদাহরণটি দেখুন:

static final int MAX_ITERATIONS = 50000;
static final int CALC_AVG_EVERY = 10000;

public static void main(String[] args) {
    printBytecodeVersion();
    printJavaVersion();
    case1();//str.concat
    case2();//+=
    case3();//StringBuilder
}

static void case1() {
    System.out.println("[str1.concat(str2)]");
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    String str = "";
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str = str.concat(UUID.randomUUID() + "---");
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}

static void case2() {
    System.out.println("[str1+=str2]");
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    String str = "";
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str += UUID.randomUUID() + "---";
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}

static void case3() {
    System.out.println("[str1.append(str2)]");
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    StringBuilder str = new StringBuilder("");
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str.append(UUID.randomUUID() + "---");
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");

}

static void saveTime(List<Long> executionTimes, long startTime) {
    executionTimes.add(System.currentTimeMillis() - startTime);
    if (executionTimes.size() % CALC_AVG_EVERY == 0) {
        out.println("average time for " + executionTimes.size() + " concatenations: "
                + NumberFormat.getInstance().format(executionTimes.stream().mapToLong(Long::longValue).average().orElseGet(() -> 0))
                + " ms avg");
        executionTimes.clear();
    }
}

আউটপুট:

জাভা বাইটকোড সংস্করণ: 8
java.version: 1.8.0_144
[str1.concat (str2)]
গড় 10000 concatenations জন্য সময়: 0,096 MS AVG
10000 concatenations জন্য গড় সময়: 0,185 MS AVG
10000 concatenations জন্য গড় সময়: 0,327 MS AVG
জন্য গড় সময় 10000
কনটেক্সটেশন: 0.001 এমএস গড় গড় সময় 10000 কনটেক্সটেশনের জন্য: 0.656 এমএস গড়
দৈর্ঘ্যের স্ট্রিং: 1950000 17745 এমএসে
[ স্ট্রিমিটি = = স্ট্রিপ]
10000 কনটেক্সটনের জন্য গড় সময়: 0.21 এমএস গড়
10000 সূক্ষ্মতার
জন্য গড় সময় : 0.652 এমএস গড় গড় সময় 10000 কনটেনটেশনস: 10000 কনটেনটেশনের
জন্য 1.129 এমএস গড় গড় সময়: 1.727 এমএস গড়
10000 concatenations জন্য গড় সময়: 2,302 MS AVG
দৈর্ঘ্যের স্ট্রিং তৈরি হয়েছে: 1950000 60279 এমএসে
[str1.append (str2)]
10000 কনটেনটেশনের জন্য গড় সময়: 0.002 এমএস গড়
গড় সময় 10000 কনট্যাকটেশনের জন্য: 0.002 এমএস গড়
গড় সময় 10000 কনট্যাকটেশনের জন্য: 0.002 এমএস গড়
গড় সময় 10000 কনট্যাকটেশনের জন্য:
10000
কনটেনটেশনের জন্য 0.002 এমএস গড় গড় সময়: 0.002 এমএস গড় দৈর্ঘ্যের স্ট্রিং তৈরি: 1950000 100 এমএসে

স্ট্রিংয়ের দৈর্ঘ্য বাড়ার সাথে সাথে সংক্ষিপ্তকরণের সময়ও বাড়বে।
সেখানেই StringBuilderঅবশ্যই প্রযোজ্য।
আপনি যেমন দেখতে পাচ্ছেন, উপসংহার:, UUID.randomUUID()+"---"সময়কে সত্যই প্রভাবিত করে না।

পিএস: আমি মনে করি না জাভাতে স্ট্রিংবিল্ডার কখন ব্যবহার করবেন এটি সত্যই এর একটি সদৃশ।
এই প্রশ্নটি সম্পর্কে আলোচনা করে toString()যা বেশিরভাগ সময় বিশাল স্ট্রিংগুলির সংমিশ্রণ সম্পাদন করে না।


2019 আপডেট

সময় থেকে java8, জিনিস কিছু পরিবর্তন হয়েছে। মনে হচ্ছে যে NOW (java13), এর সংযুক্তকরণের সময় +=কার্যত হিসাবে একই str.concat()। তবে StringBuilderকনকনেটেশন সময় এখনও ধ্রুবক । (আরও ভার্বোজ আউটপুট যোগ করার জন্য উপরের মূল পোস্টটি কিছুটা সম্পাদনা করা হয়েছিল)

জাভা বাইটকোড সংস্করণ: 13
java.version: 13.0.1
[str1.concat (str2)]
10000 কনটেনটেশনের জন্য গড় সময়: 0.000 এমএস গড় 10000 কনটেনটেশনের জন্য
গড় সময়: 0.1 এমএস গড়
গড় সময় 10000 কনট্যাকটেশনের জন্য: 0.17 এমএস গড়
গড় সময় 10000 concatenations: 0,255 MS AVG
10000 concatenations জন্য গড় সময়: 0,336 MS AVG
1950000 মধ্যে: তৈরি হয়েছে দৈর্ঘ্যের স্ট্রিং 9147 MS
[str1 + + = str2]
10000 concatenations জন্য গড় সময়: 0,037 MS AVG
10000 concatenations জন্য গড় সময়: 0,097 MS AVG
জন্য গড় সময় 10000
কনটেনটেশনস: 10000 কনটেনটেশনের জন্য 0.249 এমএস গড় গড় সময়: 0.298 এমএস গড়
10000 কনটেনটেশনের জন্য গড় সময়: 0.326 এমএস গড়
দৈর্ঘ্যের স্ট্রিং তৈরি হয়েছে: ১৯৯০০০ - ১০১৯১ এমএসে
[স্ট্রাই.এপেন্ড (স্ট্রপ ২)]
গড় সময় 10000 কনট্যাকটেশনগুলির জন্য: 0.001 এমএস গড়
গড় সময় 10000 কনট্যাকটনেশন: 0.001 এমএস গড়
গড় সময় 10000 কনট্যাকটনেশন: 0.001 এমএস গড়
গড় সময় 10000 কনট্যাকটেশনের জন্য:
10000
কনটেনটেশনের জন্য 0.001 এমএস গড় গড় সময়: 0.001 এমএস গড় দৈর্ঘ্যের স্ট্রিং তৈরি: 1950000 43 এমএসে

মূল্যবান লক্ষণীয়ও bytecode:8/java.version:13সমন্বয়ের তুলনায় একটি ভাল পারফরম্যান্স সুবিধা আছেbytecode:8/java.version:8


এটি গ্রহণযোগ্য উত্তর হওয়া উচিত .. এটি স্ট্রিং স্ট্রিমের আকারের উপর নির্ভর করে যা কনক্যাট বা স্ট্রিংবিল্ডারের পছন্দ নির্ধারণ করে
user1428716

@ ব্যবহারকারী1428716 এফওয়াইআই: উত্তরগুলি আপডেট হয়েছে java13যা ফলাফলগুলি এখন পৃথক with তবে আমি মনে করি মূল উপসংহারটি একই রয়ে গেছে।
মেরিনোস

7

অ্যাপাচি কমন্স-ল্যাংয়ের একটি ToStringBuilder শ্রেণি রয়েছে যা ব্যবহার করা অত্যন্ত সহজ। এটি অ্যাপড-লজিক পরিচালনা করার পাশাপাশি আপনার কীভাবে আপনার টস্ট্রিং দেখতে চান তা ফর্ম্যাট করার উভয়ের পক্ষে একটি দুর্দান্ত কাজ।

public void toString() {
     ToStringBuilder tsb =  new ToStringBuilder(this);
     tsb.append("a", a);
     tsb.append("b", b)
     return tsb.toString();
}

মত দেখাচ্ছে আউটপুট ফিরে আসবে com.blah.YourClass@abc1321f[a=whatever, b=foo]

অথবা চেইন ব্যবহার করে আরও ঘনীভূত আকারে:

public void toString() {
     return new ToStringBuilder(this).append("a", a).append("b", b").toString();
}

অথবা আপনি যদি শ্রেণীর প্রতিটি ক্ষেত্র অন্তর্ভুক্ত করতে প্রতিবিম্বটি ব্যবহার করতে চান:

public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

আপনি চাইলে টোস্ট্রিংয়ের স্টাইলটিও কাস্টমাইজ করতে পারেন।


4

আপনি যতটা সম্ভব টুস্ট্রিং পদ্ধতিটিকে পঠনযোগ্য করে তুলুন!

আমার বইয়ের এটির একমাত্র ব্যতিক্রম হ'ল যদি আপনি আমাকে প্রমাণ করতে পারেন যে এটি উল্লেখযোগ্য সংস্থান গ্রহণ করেছে :) (হ্যাঁ, এর অর্থ প্রোফাইলিং)

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


3

স্ট্রিংবিল্ডার ব্যবহারকারীর বর্তমান সংকলকগুলির সাথে এখনও প্রয়োজনীয় কিনা তা নিয়ে কিছুটা বিতর্ক রয়েছে বলে মনে হয়। তাই আমি ভেবেছিলাম আমার 2 সেন্ট অভিজ্ঞতা দেব।

আমার কাছে JDBC10 কে রেকর্ডের ফলাফল রয়েছে (হ্যাঁ, আমার একটি ব্যাচে তাদের সমস্ত দরকার need) + অপারেটরটি ব্যবহার করতে আমার মেশিনে প্রায় 5 মিনিট সময় লাগে Java 1.8stringBuilder.append("")একই ক্যোয়ারির জন্য ব্যবহার করা এক সেকেন্ডেরও কম সময় নেয়।

সুতরাং পার্থক্য বিশাল। একটি লুপের ভিতরে StringBuilderঅনেক দ্রুত faster


2
আমি মনে করি বিতর্কটি লুপগুলির বাইরে এটি ব্যবহার সম্পর্কে। আমি মনে করি একটি লুপের ভিতরে এটি ব্যবহার করার জন্য আপনার aক্যমত্য রয়েছে।
জর্দান

2

'+' ব্যবহার করে পারফরম্যান্স অনুসারে স্ট্রিং কনটেনটেশন ব্যয়বহুল কারণ স্ট্রিংস জাভাতে পরিবর্তনহীন হওয়ায় স্ট্রিংয়ের সম্পূর্ণ নতুন কপি তৈরি করতে হয়। কনটেনটেশন খুব ঘন ঘন হলে এটি বিশেষ ভূমিকা পালন করে, যেমন: একটি লুপের অভ্যন্তরে। আমি যখন এই জাতীয় কাজ করার চেষ্টা করি তখন আমার আইডিইএ পরামর্শ দেয়:

এখানে চিত্র বর্ণনা লিখুন

সপ্তাহের দিন:

  • একটি একক স্ট্রিং অ্যাসাইনমেন্টের মধ্যে স্ট্রিং কনটেনটেশন ব্যবহার করা ভাল।
  • আপনি যদি চরিত্রের ডেটার একটি বৃহত ব্লক তৈরি করতে লুপিং করেন তবে স্ট্রিংবফারের জন্য যান।
  • একটি স্ট্রিংয়ের উপর + = ব্যবহার করা সর্বদা স্ট্রিংবুফার ব্যবহারের চেয়ে কম দক্ষ হতে চলেছে, তাই এটি সতর্কবার্তের ঘণ্টা বাজে উচিত - তবে কিছু ক্ষেত্রে প্রাপ্ত অপটিমাইজেশনটি পঠনযোগ্যতার সমস্যার তুলনায় নগণ্য হবে, সুতরাং আপনার সাধারণ জ্ঞানটি ব্যবহার করুন।

এই বিষয়টির চারপাশে এখানে একটি দুর্দান্ত জোন স্কিটি ব্লগ


2
আপনার একাধিক থ্রেড থেকে সিঙ্ক্রোনাইজ অ্যাক্সেসের প্রয়োজন না হলে স্ট্রিংবাফার কখনও ব্যবহার করা উচিত নয়। অন্যথায় স্ট্রিংবিল্ডারটিকে পছন্দ করুন যা সিঙ্ক্রোনাইজ করা হয়নি এবং এতে কম ওভারহেড রয়েছে।
এরকি ডার লুনি

1

আমি কী উল্লেখ করতে পারি যে আপনি যদি কোনও সংগ্রহ ঘন ঘন ঘন ঘন ঘন ঘন স্ট্রিংবিল্ডার ব্যবহার করতে চলেছেন তবে আপনি অ্যাপাচি কমন্স ল্যাং এবং স্ট্রিংইটিলস.জাইন () (বিভিন্ন স্বাদে) পরীক্ষা করে দেখতে চাইতে পারেন ?

কর্মক্ষমতা হোক না কেন, আপনার StringBuilders তৈরি করতে থাকার এবং কি মত মনে হয় জন্য loops জন্য সংরক্ষণ করব দশলক্ষ ভাগের ভাগ সময়।


1

আমি জাভা 8 এ যা যা চেক করেছি তা এখানে

  • স্ট্রিং কনটেনটেশন ব্যবহার করে
  • স্ট্রিংবিল্ডার ব্যবহার করে

    long time1 = System.currentTimeMillis();
    usingStringConcatenation(100000);
    System.out.println("usingStringConcatenation " + (System.currentTimeMillis() - time1) + " ms");
    
    time1 = System.currentTimeMillis();
    usingStringBuilder(100000);
    System.out.println("usingStringBuilder " + (System.currentTimeMillis() - time1) + " ms");
    
    
    private static void usingStringBuilder(int n)
    {
        StringBuilder str = new StringBuilder();
        for(int i=0;i<n;i++)
            str.append("myBigString");    
    }
    
    private static void usingStringConcatenation(int n)
    {
        String str = "";
        for(int i=0;i<n;i++)
            str+="myBigString";
    }

যদি আপনি প্রচুর পরিমাণে স্ট্রিংয়ের জন্য স্ট্রিং কনটেনটেশন ব্যবহার করেন তবে এটি সত্যিই একটি দুঃস্বপ্ন।

usingStringConcatenation 29321 ms
usingStringBuilder 2 ms

-1

আমি মনে করি স্ট্রিংবিল্ডার অ্যাপেন্ড পদ্ধতির সাথে আমাদের উচিত। কারণ হওয়ার কারণ:

  1. স্ট্রিং কনকেনেটেট প্রতিবার একটি নতুন স্ট্রিং অবজেক্ট তৈরি করবে (স্ট্রিং যেমন অপরিবর্তনীয় বস্তু), সুতরাং এটি 3 টি অবজেক্ট তৈরি করবে।

  2. স্ট্রিং বিল্ডারের সাহায্যে কেবলমাত্র একটি অবজেক্ট তৈরি হবে [স্ট্রিংবিল্ডার পরিবর্তনযোগ্য) এবং পরবর্তী স্ট্রিং এতে যুক্ত হয়ে যাবে।


কেন এই উত্তরটি নিম্নমানের? docs.oracle.com/javase/8/docs/api/java/util/stream/… - পারস্পরিক পরিবর্তন হ্রাস
ব্যবহারকারী 1428716

-4

এর মতো সরল স্ট্রিংয়ের জন্য আমি ব্যবহার করতে পছন্দ করি

"string".concat("string").concat("string");

ক্রমানুসারে, আমি বলব স্ট্রিং তৈরির পছন্দের পদ্ধতিটি স্ট্রিংবিল্ডার, স্ট্রিং # কনক্যাট (), তারপরে ওভারলোডেড + অপারেটর ব্যবহার করে। স্ট্রিংবিল্ডার যখন একটি বড় স্ট্রিং কাজ করে ঠিক তেমনি + অপারেটর ব্যবহারের ক্ষেত্রে পারফরম্যান্সের একটি বড় হ্রাস (স্ট্রিংয়ের আকার বাড়ার সাথে সাথে তাত্পর্যপূর্ণভাবে বড় হ্রাস) একটি তাত্পর্যপূর্ণ পারফরম্যান্স বৃদ্ধি। .Concat () ব্যবহার করে একটি সমস্যা হ'ল এটি নুলপয়েন্টারএক্সেপশনগুলি ফেলে দিতে পারে।


9
কনক্যাট () ব্যবহারের ফলে '+' এর চেয়ে খারাপ ফলাফল হতে পারে যেহেতু জেএলএস '+' কে স্ট্রিংবিল্ডারে রূপান্তর করতে দেয় এবং সম্ভবত সমস্ত জেভিএম এর কাজটি করে বা আরও কার্যকর বিকল্প ব্যবহার করে - সম্ভবত এটি একই ক্ষেত্রে সত্য হবে না কনক্যাট যা আপনার উদাহরণে কমপক্ষে একটি সম্পূর্ণ মধ্যবর্তী স্ট্রিং তৈরি এবং বাতিল করতে হবে।
লরেন্স ডল 17
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.