มันเป็นการปฏิบัติที่ดีกว่าหรือไม่ที่จะใช้ String.format ผ่านการต่อสตริงใน Java?


273

มีความแตกต่างที่สังเกตเห็นได้ระหว่างการใช้String.formatและการต่อข้อมูลสตริงใน Java หรือไม่?

ฉันมักจะใช้String.formatแต่บางครั้งจะลื่นและใช้การเรียงต่อกัน ฉันสงสัยว่าคนใดคนหนึ่งดีกว่าคนอื่น

วิธีที่ฉันเห็นมันString.formatให้พลังมากขึ้นในการ "จัดรูปแบบ" สตริง และการต่อข้อมูลหมายความว่าคุณไม่ต้องกังวลกับการใส่% s พิเศษหรือไม่ได้ใช้งาน

String.format ก็สั้น

อันไหนที่อ่านได้มากขึ้นขึ้นอยู่กับว่าหัวคุณทำงานอย่างไร


ฉันคิดว่าเราสามารถไปกับ MessageFormat.format โปรดดูคำตอบstackoverflow.com/a/56377112/1491414สำหรับข้อมูลเพิ่มเติม
Ganesa Vijayakumar

คำตอบ:


242

String.format()ผมขอแนะนำว่ามันคือการปฏิบัติที่ดีกว่าที่จะใช้ เหตุผลหลักคือString.format()สามารถแปลเป็นภาษาท้องถิ่นได้ง่ายขึ้นด้วยข้อความที่โหลดจากไฟล์ทรัพยากรในขณะที่การต่อข้อมูลไม่สามารถแปลเป็นภาษาท้องถิ่นได้โดยไม่ต้องสร้างโปรแกรมใหม่ที่มีรหัสแตกต่างกันสำหรับแต่ละภาษา

หากคุณวางแผนในแอปของคุณให้เป็นภาษาท้องถิ่นคุณควรสร้างนิสัยในการระบุตำแหน่งอาร์กิวเมนต์สำหรับโทเค็นรูปแบบของคุณด้วย:

"Hello %1$s the time is %2$t"

สิ่งนี้สามารถถูกแปลเป็นภาษาท้องถิ่นและมีการเปลี่ยนชื่อและโทเค็นเวลาโดยไม่ต้องมีการคอมไพล์ซ้ำของการปฏิบัติการเพื่อบัญชีสำหรับการสั่งซื้อที่แตกต่างกัน ด้วยตำแหน่งอาร์กิวเมนต์คุณยังสามารถใช้อาร์กิวเมนต์เดิมอีกครั้งโดยไม่ส่งผ่านเข้าไปในฟังก์ชันสองครั้ง:

String.format("Hello %1$s, your name is %1$s and the time is %2$t", name, time)

1
คุณช่วยชี้ให้ฉันดูเอกสารบางอย่างที่พูดถึงวิธีการทำงานกับตำแหน่งอาร์กิวเมนต์ / คำสั่งใน Java (เช่นวิธีอ้างอิงอาร์กิวเมนต์ตามตำแหน่ง) ขอบคุณ
markvgti

13
ดีกว่าไม่สายรุ่น Java สุ่ม: docs.oracle.com/javase/1.5.0/docs/api/java/util/…
Aksel

174

เกี่ยวกับประสิทธิภาพ:

public static void main(String[] args) throws Exception {      
  long start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
    String s = "Hi " + i + "; Hi to you " + i*2;
  }
  long end = System.currentTimeMillis();
  System.out.println("Concatenation = " + ((end - start)) + " millisecond") ;

  start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
    String s = String.format("Hi %s; Hi to you %s",i, + i*2);
  }
  end = System.currentTimeMillis();
  System.out.println("Format = " + ((end - start)) + " millisecond");
}

ผลการจับเวลามีดังนี้:

  • การต่อข้อมูล = 265 มิลลิวินาที
  • รูปแบบ = 4141 มิลลิวินาที

ดังนั้นการต่อข้อมูลจะเร็วกว่า String.format มาก


15
พวกเขาล้วนเป็นแนวปฏิบัติที่เลวร้าย ใช้ StringBuilder
Amir Raminfar

8
StringBuilder อยู่นอกขอบเขตที่นี่ (คำถาม OP เกี่ยวกับการเปรียบเทียบ String.format กับการต่อสตริง) แต่คุณแสดงข้อมูลเกี่ยวกับ String Builder หรือไม่
Icaro

108
@AmirRaminar: คอมไพเลอร์แปลง "+" เพื่อโทรไปยัง StringBuilder โดยอัตโนมัติ
Martin Schröder

40
@ MartinSchröder: หากคุณเรียกใช้javap -c StringTest.classคุณจะเห็นว่าคอมไพเลอร์แปลง "+" เป็น StringBuilder โดยอัตโนมัติเฉพาะเมื่อคุณไม่ได้อยู่ในลูป หากการต่อข้อมูลทั้งหมดเสร็จสิ้นในบรรทัดเดียวมันก็เหมือนกับการใช้ '+' แต่ถ้าคุณใช้myString += "morechars";หรือmyString += anotherString;หลายบรรทัดคุณจะสังเกตเห็นว่าอาจมีการสร้าง StringBuilder มากกว่าหนึ่งรายการดังนั้นการใช้ "+" อาจไม่ได้ผลเสมอไป เป็น StringBuilder
ccpizza

7
@ Joffrey: สิ่งที่ฉันหมายถึงคือลูป+ไม่ได้ถูกแปลงเป็นStringBuilder.append()แต่new StringBuilder()จะเกิดขึ้นในการทำซ้ำแต่ละครั้ง
ccpizza

39

เนื่องจากมีการอภิปรายเกี่ยวกับประสิทธิภาพฉันคิดว่าฉันจะเพิ่มในการเปรียบเทียบที่รวม StringBuilder ในความเป็นจริงมันเร็วกว่า concat และโดยปกติแล้วตัวเลือก String.format

เพื่อให้การเปรียบเทียบแอปเปิ้ลกับแอปเปิ้ลเปรียบเทียบฉันยกตัวอย่าง StringBuilder ใหม่ในลูปแทนที่จะเป็นข้างนอก (อันที่จริงแล้วเร็วกว่าการทำอินสแตนซ์เพียงครั้งเดียวที่น่าจะเกิดขึ้นเนื่องจากโอเวอร์เฮดของการจัดสรรพื้นที่ใหม่ ผู้สร้างเดียว)

    String formatString = "Hi %s; Hi to you %s";

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s = String.format(formatString, i, +i * 2);
    }

    long end = System.currentTimeMillis();
    log.info("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        String s = "Hi " + i + "; Hi to you " + i * 2;
    }

    end = System.currentTimeMillis();

    log.info("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        StringBuilder bldString = new StringBuilder("Hi ");
        bldString.append(i).append("; Hi to you ").append(i * 2);
    }

    end = System.currentTimeMillis();

    log.info("String Builder = " + ((end - start)) + " millisecond");
  • 2012-01-11 16: 30: 46,058 INFO [TestMain] - รูปแบบ = 1416 มิลลิวินาที
  • 2012-01-11 16: 30: 46,190 INFO [TestMain] - การต่อข้อมูล = 134 มิลลิวินาที
  • 2012-01-11 16: 30: 46,313 INFO [TestMain] - เครื่องมือสร้างสตริง = 117 มิลลิวินาที

21
การทดสอบ StringBuilder ไม่ได้เรียก toString () ดังนั้นจึงไม่ใช่การเปรียบเทียบที่ยุติธรรม ฉันสงสัยว่าคุณจะพบว่ามันอยู่ในข้อผิดพลาดการวัดประสิทธิภาพของการต่อข้อมูลถ้าคุณแก้ไขข้อผิดพลาดนั้น
Jamey Sharp

15
ในการทดสอบการต่อข้อมูลและการจัดรูปแบบคุณถาม a String. การทดสอบ StringBuilder นั้นยุติธรรมต้องมีขั้นตอนสุดท้ายที่จะเปลี่ยนเนื้อหาของ StringBuilder ให้เป็นสตริง bldString.toString()คุณทำได้โดยการโทร ฉันหวังว่าจะอธิบายมันได้หรือไม่
Jamey Sharp

4
Jamey Sharp พูดถูก การเรียกใช้ bldString.toString () นั้นใกล้เคียงกันหากไม่ช้ากว่าการต่อสตริง
Akos Cz

3
String s = bldString.toString(); กำหนดเวลาอยู่กับการเรียงต่อกันและ StringBuilder เกือบเสมอกับแต่ละอื่น ๆ : Format = 1520 millisecond, Concatenation = 167 millisecond, String Builder = 173 millisecond ฉันวิ่งพวกเขาในวงและเฉลี่ยแต่ละออกเพื่อให้ได้ตัวแทนที่ดี (การเพิ่มประสิทธิภาพก่อน JVM จะพยายามห่วง 10000+ เมื่อฉันได้รับเวลา)
TechTrip

3
พวกคุณรู้ได้อย่างไรว่าโค้ดถูกเรียกใช้งานทั้งหมด? ตัวแปรไม่เคยอ่านหรือใช้คุณไม่สามารถแน่ใจได้ว่า JIT จะไม่ลบรหัสนี้ในครั้งแรก
alobodzk

37

ปัญหาหนึ่ง.formatคือว่าคุณสูญเสียความปลอดภัยประเภทคงที่ คุณสามารถมีอาร์กิวเมนต์น้อยเกินไปสำหรับรูปแบบของคุณและคุณสามารถมีประเภทที่ไม่ถูกต้องสำหรับตัวระบุรูปแบบ - ทั้งที่นำไปสู่การIllegalFormatException ที่รันไทม์ดังนั้นคุณอาจจบลงด้วยการบันทึกรหัสที่หยุดการผลิต

ในทางตรงกันข้ามข้อโต้แย้งที่+สามารถทดสอบได้โดยคอมไพเลอร์

ประวัติของการรักษาความปลอดภัยของ(ซึ่งformatฟังก์ชั่นนั้นเป็นแบบอย่าง) นั้นยาวและน่ากลัว


16
เพียงเพื่อบันทึก IDEs ที่ทันสมัย ​​(เช่น IntelliJ) ช่วยในการนับข้อโต้แย้งและการจับคู่ประเภท
Ron Klein

2
จุดที่ดีเกี่ยวกับการรวบรวมผมแนะนำให้คุณทำการตรวจสอบเหล่านี้ผ่าน FindBugs (ซึ่งสามารถทำงานใน IDE หรือผ่าน Maven ในระหว่างการสร้าง) โปรดทราบว่าสิ่งนี้จะตรวจสอบการจัดรูปแบบในการบันทึกของคุณทั้งหมด! สิ่งนี้ใช้ได้โดยไม่คำนึงถึงผู้ใช้ IDE
Christophe Roussy

20

อันไหนที่อ่านได้มากขึ้นขึ้นอยู่กับว่าหัวคุณทำงานอย่างไร

คุณได้รับคำตอบที่นั่น

มันเป็นเรื่องของรสนิยมส่วนตัว

การต่อข้อมูลสตริงเร็วกว่าเล็กน้อยฉันคิดว่า แต่ควรจะเล็กน้อย


3
ฉันเห็นด้วย. การคิดเกี่ยวกับความแตกต่างด้านประสิทธิภาพที่นี่ส่วนใหญ่เป็นเพียงการปรับให้เหมาะสมก่อนกำหนด - ในเหตุการณ์ที่ไม่น่าเป็นไปได้ที่การรวบรวมสถานะแสดงว่ามีปัญหาที่นี่จากนั้นจึงกังวล
Jonik

3
เป็นเรื่องของรสนิยมส่วนตัวเท่านั้นหากโครงการมีขนาดเล็กและไม่เคยตั้งใจที่จะเป็นสากลในแง่ที่มีความหมายใด ๆ ไม่เช่นนั้น String.format จะชนะการเรียงต่อกันในทุก ๆ ทาง
workmad3

4
ฉันไม่เห็นด้วย. ไม่ว่าโครงการจะมีขนาดใหญ่แค่ไหนคุณก็แทบจะไม่ จำกัด วงทุกสตริงที่เคยสร้างขึ้นมา มันขึ้นอยู่กับสถานการณ์ (สตริงที่ใช้)
Jonik

ฉันไม่สามารถจินตนาการได้ว่าใครจะพิจารณา 'String.format ("% s% s", a, b)' เพื่อให้อ่านได้ง่ายกว่า 'a + b' และให้ลำดับความเร็วที่แตกต่างกัน คำตอบนั้นชัดเจนสำหรับฉัน (ในสถานการณ์ที่ไม่จำเป็นต้องมีการแปลเป็นภาษาท้องถิ่นเช่น debug หรือข้อความการบันทึกส่วนใหญ่)
BobDoolittle

16

นี่คือการทดสอบที่มีขนาดตัวอย่างหลายหน่วยเป็นมิลลิวินาที

public class Time {

public static String sysFile = "/sys/class/camera/rear/rear_flash";
public static String cmdString = "echo %s > " + sysFile;

public static void main(String[] args) {

  int i = 1;
  for(int run=1; run <= 12; run++){
      for(int test =1; test <= 2 ; test++){
        System.out.println(
                String.format("\nTEST: %s, RUN: %s, Iterations: %s",run,test,i));
        test(run, i);
      }
      System.out.println("\n____________________________");
      i = i*3;
  }
}

public static void test(int run, int iterations){

      long start = System.nanoTime();
      for( int i=0;i<iterations; i++){
          String s = "echo " + i + " > "+ sysFile;
      }
      long t = System.nanoTime() - start;   
      String r = String.format("  %-13s =%10d %s", "Concatenation",t,"nanosecond");
      System.out.println(r) ;


     start = System.nanoTime();       
     for( int i=0;i<iterations; i++){
         String s =  String.format(cmdString, i);
     }
     t = System.nanoTime() - start; 
     r = String.format("  %-13s =%10d %s", "Format",t,"nanosecond");
     System.out.println(r);

      start = System.nanoTime();          
      for( int i=0;i<iterations; i++){
          StringBuilder b = new StringBuilder("echo ");
          b.append(i).append(" > ").append(sysFile);
          String s = b.toString();
      }
     t = System.nanoTime() - start; 
     r = String.format("  %-13s =%10d %s", "StringBuilder",t,"nanosecond");
     System.out.println(r);
}

}

TEST: 1, RUN: 1, Iterations: 1
  Concatenation =     14911 nanosecond
  Format        =     45026 nanosecond
  StringBuilder =      3509 nanosecond

TEST: 1, RUN: 2, Iterations: 1
  Concatenation =      3509 nanosecond
  Format        =     38594 nanosecond
  StringBuilder =      3509 nanosecond

____________________________

TEST: 2, RUN: 1, Iterations: 3
  Concatenation =      8479 nanosecond
  Format        =     94438 nanosecond
  StringBuilder =      5263 nanosecond

TEST: 2, RUN: 2, Iterations: 3
  Concatenation =      4970 nanosecond
  Format        =     92976 nanosecond
  StringBuilder =      5848 nanosecond

____________________________

TEST: 3, RUN: 1, Iterations: 9
  Concatenation =     11403 nanosecond
  Format        =    287115 nanosecond
  StringBuilder =     14326 nanosecond

TEST: 3, RUN: 2, Iterations: 9
  Concatenation =     12280 nanosecond
  Format        =    209051 nanosecond
  StringBuilder =     11818 nanosecond

____________________________

TEST: 5, RUN: 1, Iterations: 81
  Concatenation =     54383 nanosecond
  Format        =   1503113 nanosecond
  StringBuilder =     40056 nanosecond

TEST: 5, RUN: 2, Iterations: 81
  Concatenation =     44149 nanosecond
  Format        =   1264241 nanosecond
  StringBuilder =     34208 nanosecond

____________________________

TEST: 6, RUN: 1, Iterations: 243
  Concatenation =     76018 nanosecond
  Format        =   3210891 nanosecond
  StringBuilder =     76603 nanosecond

TEST: 6, RUN: 2, Iterations: 243
  Concatenation =     91222 nanosecond
  Format        =   2716773 nanosecond
  StringBuilder =     73972 nanosecond

____________________________

TEST: 8, RUN: 1, Iterations: 2187
  Concatenation =    527450 nanosecond
  Format        =  10291108 nanosecond
  StringBuilder =    885027 nanosecond

TEST: 8, RUN: 2, Iterations: 2187
  Concatenation =    526865 nanosecond
  Format        =   6294307 nanosecond
  StringBuilder =    591773 nanosecond

____________________________

TEST: 10, RUN: 1, Iterations: 19683
  Concatenation =   4592961 nanosecond
  Format        =  60114307 nanosecond
  StringBuilder =   2129387 nanosecond

TEST: 10, RUN: 2, Iterations: 19683
  Concatenation =   1850166 nanosecond
  Format        =  35940524 nanosecond
  StringBuilder =   1885544 nanosecond

  ____________________________

TEST: 12, RUN: 1, Iterations: 177147
  Concatenation =  26847286 nanosecond
  Format        = 126332877 nanosecond
  StringBuilder =  17578914 nanosecond

TEST: 12, RUN: 2, Iterations: 177147
  Concatenation =  24405056 nanosecond
  Format        = 129707207 nanosecond
  StringBuilder =  12253840 nanosecond

1
StringBuilder เป็นวิธีที่เร็วที่สุดเมื่อคุณต่อท้ายอักขระในลูปตัวอย่างเช่นเมื่อคุณต้องการสร้างสตริงที่มีหนึ่งพัน 1 โดยการเพิ่มทีละตัว นี่คือข้อมูลเพิ่มเติม: pellegrino.link/2015/08/22/…
Carlos Hoyos

ฉันชอบวิธีที่คุณใช้ String.format สำหรับเอาต์พุตเสมอ: D ดังนั้นจึงมีข้อดี และพูดตามตรงถ้าเราไม่ได้พูดถึงการทำซ้ำหลายล้านครั้งฉันชอบ string.format สำหรับการอ่านเนื่องจากรหัสของคุณแสดงให้เห็นถึงข้อได้เปรียบที่ชัดเจน
mohamnag

9

นี่คือการทดสอบเช่นเดียวกับข้างต้นด้วยการปรับเปลี่ยนการเรียกที่toString ()วิธีการในStringBuilder ผลลัพธ์ด้านล่างแสดงให้เห็นว่าวิธีการของ StringBuilder นั้นช้ากว่าการต่อข้อมูลสตริงเพียงเล็กน้อยโดยใช้ตัวดำเนินการ+

ไฟล์: StringTest.java

class StringTest {

  public static void main(String[] args) {

    String formatString = "Hi %s; Hi to you %s";

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s = String.format(formatString, i, +i * 2);
    }

    long end = System.currentTimeMillis();
    System.out.println("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        String s = "Hi " + i + "; Hi to you " + i * 2;
    }

    end = System.currentTimeMillis();

    System.out.println("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        StringBuilder bldString = new StringBuilder("Hi ");
        bldString.append(i).append("Hi to you ").append(i * 2).toString();
    }

    end = System.currentTimeMillis();

    System.out.println("String Builder = " + ((end - start)) + " millisecond");

  }
}

คำสั่งเชลล์: (คอมไพล์และรัน StringTest 5 ครั้ง)

> javac StringTest.java
> sh -c "for i in \$(seq 1 5); do echo \"Run \${i}\"; java StringTest; done"

ผล :

Run 1
Format = 1290 millisecond
Concatenation = 115 millisecond
String Builder = 130 millisecond

Run 2
Format = 1265 millisecond
Concatenation = 114 millisecond
String Builder = 126 millisecond

Run 3
Format = 1303 millisecond
Concatenation = 114 millisecond
String Builder = 127 millisecond

Run 4
Format = 1297 millisecond
Concatenation = 114 millisecond
String Builder = 127 millisecond

Run 5
Format = 1270 millisecond
Concatenation = 114 millisecond
String Builder = 126 millisecond

6

String.format()เป็นมากกว่าแค่การต่อสตริง String.format()ตัวอย่างเช่นคุณสามารถแสดงตัวเลขในสถานที่เฉพาะเจาะจงโดยใช้

อย่างไรก็ตามหากคุณไม่สนใจเกี่ยวกับการแปลจะไม่มีความแตกต่างด้านหน้าที่การใช้งาน อาจจะเร็วกว่าอีกอันหนึ่ง แต่ในกรณีส่วนใหญ่มันจะเล็กน้อย ..


4

String.formatโดยทั่วไปสตริงควรจะมากกว่าที่ต้องการ หลังมีสองข้อเสียเปรียบหลัก:

  1. มันไม่ได้เข้ารหัสสตริงที่จะสร้างในลักษณะท้องถิ่น
  2. กระบวนการสร้างถูกเข้ารหัสในสตริง

โดยจุดที่ 1 ฉันหมายถึงว่าเป็นไปไม่ได้ที่จะเข้าใจว่าการString.format()โทรกำลังทำอะไรในการส่งผ่านแบบลำดับเดียว หนึ่งถูกบังคับให้ย้อนกลับไปมาระหว่างสตริงรูปแบบและข้อโต้แย้งในขณะที่นับตำแหน่งของข้อโต้แย้ง สำหรับการต่อข้อมูลสั้น ๆ นี่ไม่ใช่ปัญหามากนัก อย่างไรก็ตามในกรณีเหล่านี้การต่อข้อมูลสตริงจะละเอียดน้อยลง

ตามจุดที่ 2 ฉันหมายถึงส่วนสำคัญของกระบวนการสร้างนั้นถูกเข้ารหัสในสตริงรูปแบบ (โดยใช้ DSL) การใช้สตริงเพื่อแสดงรหัสมีข้อเสียมากมาย มันไม่ได้ปลอดภัยพิมพ์โดยเนื้อแท้และซับซ้อนเน้นไวยากรณ์การวิเคราะห์รหัสการเพิ่มประสิทธิภาพ ฯลฯ

แน่นอนเมื่อใช้เครื่องมือหรือกรอบภายนอกภาษาจาวาปัจจัยใหม่สามารถเข้ามาเล่น


2

ฉันไม่ได้ทำการวัดประสิทธิภาพที่เฉพาะเจาะจง แต่ฉันคิดว่าการต่อข้อมูลอาจเร็วขึ้น String.format () สร้าง Formatter ใหม่ซึ่งในทางกลับกันจะสร้าง StringBuilder ใหม่ (ขนาด 16 ตัวอักษรเท่านั้น) นั่นเป็นจำนวนค่าใช้จ่ายที่ยุติธรรมโดยเฉพาะอย่างยิ่งถ้าคุณกำลังจัดรูปแบบสตริงที่ยาวขึ้นและ StringBuilder จะต้องปรับขนาด

อย่างไรก็ตามการต่อข้อมูลจะมีประโยชน์น้อยกว่าและอ่านยากกว่า และเช่นเคยควรทำเกณฑ์มาตรฐานในโค้ดของคุณเพื่อดูว่าตัวไหนดีกว่า ความแตกต่างอาจเล็กน้อยในแอปเซิร์ฟเวอร์หลังจากบันเดิลทรัพยากรสถานที่และอื่น ๆ ของคุณถูกโหลดในหน่วยความจำและรหัสคือ JITted

อาจเป็นวิธีปฏิบัติที่ดีที่สุดเป็นความคิดที่ดีที่จะสร้างฟอร์แมตเตอร์ของคุณเองด้วย StringBuilder ที่มีขนาดเหมาะสม (ต่อท้าย) และโลแคลและใช้งานได้หากคุณมีการจัดรูปแบบจำนวนมาก


2

อาจมีความแตกต่างที่สังเกตเห็นได้

String.format ค่อนข้างซับซ้อนและใช้การแสดงออกปกติภายใต้ดังนั้นอย่าทำให้มันเป็นนิสัยที่จะใช้มันทุกที่ แต่เฉพาะที่คุณต้องการ

StringBuilder จะเป็นลำดับความสำคัญได้เร็วขึ้น (เป็นคนที่นี่ชี้ไปแล้ว)


1

ฉันคิดว่าเราสามารถไปกับMessageFormat.formatมันควรจะดีทั้งอ่านและด้านประสิทธิภาพ

ฉันใช้โปรแกรมเดียวกันกับที่Icaro ใช้ในคำตอบข้างต้นของเขาและฉันก็ปรับปรุงมันด้วยรหัสต่อท้ายสำหรับการใช้MessageFormatเพื่ออธิบายหมายเลขประสิทธิภาพ

  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
      String s = "Hi " + i + "; Hi to you " + i * 2;
    }
    long end = System.currentTimeMillis();
    System.out.println("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
      String s = String.format("Hi %s; Hi to you %s", i, +i * 2);
    }
    end = System.currentTimeMillis();
    System.out.println("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
      String s = MessageFormat.format("Hi %s; Hi to you %s", i, +i * 2);
    }
    end = System.currentTimeMillis();
    System.out.println("MessageFormat = " + ((end - start)) + " millisecond");
  }

การต่อข้อมูล = 69 มิลลิวินาที

รูปแบบ = 1435 มิลลิวินาที

MessageFormat = 200 มิลลิวินาที

ปรับปรุง:

ตามรายงาน SonarLint ควรใช้สตริงรูปแบบ Printf อย่างถูกต้อง (squid: S3457)

เนื่องจากprintf-styleสตริงการจัดรูปแบบถูกตีความที่รันไทม์แทนที่จะได้รับการตรวจสอบโดยคอมไพเลอร์จึงสามารถมีข้อผิดพลาดที่ทำให้เกิดสตริงที่ไม่ถูกต้อง กฎข้อนี้คงตรวจสอบความสัมพันธ์ของprintf-styleสตริงรูปแบบการขัดแย้งของพวกเขาเมื่อเรียกรูปแบบ ( ... ) วิธีการjava.util.Formatter, java.lang.String, java.io.PrintStream, MessageFormatและjava.io.PrintWriterชั้นเรียนและprintf(...)วิธีการjava.io.PrintStreamหรือjava.io.PrintWriterการเรียน

ฉันเปลี่ยนสไตล์การพิมพ์ด้วยวงเล็บปีกกาและได้ผลลัพธ์ที่น่าสนใจดังนี้

การต่อข้อมูล = 69 มิลลิวินาที
รูปแบบ = 1107 มิลลิวินาที
รูปแบบ: curly-brackets = 416 มิลลิวินาที
MessageFormat = 215 มิลลิวินาที
MessageFormat: วงเล็บเหลี่ยม = 2517 มิลลิวินาที

ข้อสรุปของฉัน:
ตามที่ฉันเน้นไว้ด้านบนการใช้ String.format กับวงเล็บปีกกาควรเป็นตัวเลือกที่ดีเพื่อให้ได้รับประโยชน์จากการอ่านที่ดีและประสิทธิภาพ


0

คุณไม่สามารถเปรียบเทียบ String Concatenation และ String.Format โดยโปรแกรมด้านบน

คุณอาจลองใช้วิธีนี้เพื่อเปลี่ยนตำแหน่งของการใช้สตริงของคุณรูปแบบและการต่อข้อมูลในบล็อกโค้ดของคุณเช่นด้านล่าง

public static void main(String[] args) throws Exception {      
  long start = System.currentTimeMillis();

  for( int i=0;i<1000000; i++){
    String s = String.format( "Hi %s; Hi to you %s",i, + i*2);
  }

  long end = System.currentTimeMillis();
  System.out.println("Format = " + ((end - start)) + " millisecond");
  start = System.currentTimeMillis();

  for( int i=0;i<1000000; i++){
    String s = "Hi " + i + "; Hi to you " + i*2;
  }

  end = System.currentTimeMillis();
  System.out.println("Concatenation = " + ((end - start)) + " millisecond") ;
}

คุณจะประหลาดใจเมื่อเห็นว่ารูปแบบทำงานได้เร็วขึ้นที่นี่ นี่คือเนื่องจากวัตถุเริ่มต้นอาจไม่ได้รับการปล่อยตัวและอาจมีปัญหากับการจัดสรรหน่วยความจำและประสิทธิภาพการทำงาน


3
คุณลองรหัสของคุณแล้วหรือยัง การต่อข้อมูลเร็วขึ้นสิบเท่าเสมอ
Icaro

มิลลิวินาทีที่ใช้ในการดำเนินการ "System.currentTimeMillis ()" นี้: P
rehan

0

ใช้เวลาเล็กน้อยในการทำความคุ้นเคยกับ String จัดรูปแบบ แต่ก็คุ้มค่าในกรณีส่วนใหญ่ ในโลกของ NRA (ไม่ต้องทำอะไรเลย) มันมีประโยชน์อย่างยิ่งที่จะเก็บข้อความโทเค็นของคุณ (การบันทึกหรือผู้ใช้) ในไลบรารีคงที่ (ฉันต้องการจำนวนคงที่ของคลาสคงที่) และเรียกพวกเขาตามความจำเป็นด้วย String.Format กำลังแปลเป็นภาษาท้องถิ่นหรือไม่ การพยายามใช้ไลบรารีด้วยวิธีการต่อข้อมูลนั้นยากที่จะอ่านแก้ไขปัญหาพิสูจน์อักษรและจัดการด้วยวิธีการใด ๆ ที่ต้องมีการต่อข้อมูล การเปลี่ยนเป็นตัวเลือก แต่ฉันสงสัยว่ามันเป็นนักแสดง หลังจากใช้งานมาหลายปีปัญหาที่ใหญ่ที่สุดของฉันกับ String รูปแบบคือความยาวของการโทรนั้นไม่สะดวกเมื่อฉันส่งผ่านไปยังฟังก์ชั่นอื่น (เช่นข่าวสารเกี่ยวกับ) แต่มันง่ายมากที่จะใช้ฟังก์ชันกำหนดเองเพื่อเป็นนามแฝง .

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.