java const string_java String、String.concat和StringBuilder性能对比

看到网上有人已经做过对比,并且贴出了代码,然后我运行了之后发现跟我分析的结论差距很大。发现他的代码有个问题,UUID.randomUUID() 首次调用耗时会很高,这个耗时被计算给了String,这对String是不公平的。

原始代码参见:http://www.codes51.com/article/detail_99554.html

修改后的测试代码如下:

importjava.util.Date;importjava.util.UUID;public classStringTest {public static voidmain(String[] args) {int testLength = 10000;

String[] arr= new String[2];

String str= "";

Date start= newDate();

String testStr=UUID.randomUUID().toString();

System.out.println("首次生成randomUUID耗时:" + (new Date().getTime() -start.getTime()));

start= newDate();for (int i = 0; i < testLength; i++) {

testStr=UUID.randomUUID().toString();

}

System.out.println("非首次生成randomUUID " + testLength + "次耗时:" + (new Date().getTime() -start.getTime()));

start= newDate();for (int i = 0; i < testLength; i++) {

str= testStr +testStr;

}

System.out.println("String 拼接测试,测试长度" + testLength + ",测试字符串数组长度" + arr.length + ",完成时间" + (new Date().getTime() -start.getTime()));

start= newDate();for (int i = 0; i < testLength; i++) {

str=testStr.concat(testStr);

}

System.out.println("String.concat 拼接测试,测试长度" + testLength + ",测试字符串数组长度" + arr.length + ",完成时间" + (new Date().getTime() -start.getTime()));

start= newDate();

StringBuilder sb;for (int i = 0; i < testLength; i++) {

str= "";

sb= newStringBuilder();for (int j = 0; j < arr.length; j++) {

sb.append(testStr);

}

str=sb.toString();

}

System.out.println("StringBuilder 拼接测试,测试长度" + testLength + ",测试字符串数组长度" + arr.length + ",完成时间" + (new Date().getTime() -start.getTime()));

}

}

测试结果:

1. 测试字符串数组长度10

首次生成randomUUID耗时:290

非首次生成randomUUID 10000次耗时:44

String 拼接测试,测试长度10000,测试字符串数组长度10,完成时间14

String 使用循环 拼接测试,测试长度10000,测试字符串数组长度10,完成时间66

String.concat 拼接测试,测试长度10000,测试字符串数组长度10,完成时间14

StringBuilder 拼接测试,测试长度10000,测试字符串数组长度10,完成时间14

2. 测试字符串数组长度5

首次生成randomUUID耗时:287

非首次生成randomUUID 10000次耗时:48

String 拼接测试,测试长度10000,测试字符串数组长度5,完成时间11

String 使用循环 拼接测试,测试长度10000,测试字符串数组长度5,完成时间20

String.concat 拼接测试,测试长度10000,测试字符串数组长度5,完成时间9

StringBuilder 拼接测试,测试长度10000,测试字符串数组长度5,完成时间10

3. 测试字符串数组长度3

首次生成randomUUID耗时:308

非首次生成randomUUID 10000次耗时:35

String 拼接测试,测试长度10000,测试字符串数组长度3,完成时间10

String 使用循环 拼接测试,测试长度10000,测试字符串数组长度3,完成时间21

String.concat 拼接测试,测试长度10000,测试字符串数组长度3,完成时间6

StringBuilder 拼接测试,测试长度10000,测试字符串数组长度3,完成时间11

4. 测试字符串数组长度2

首次生成randomUUID耗时:298

非首次生成randomUUID 10000次耗时:70

String 拼接测试,测试长度10000,测试字符串数组长度2,完成时间10

String 使用循环 拼接测试,测试长度10000,测试字符串数组长度2,完成时间8

String.concat 拼接测试,测试长度10000,测试字符串数组长度2,完成时间3

StringBuilder 拼接测试,测试长度10000,测试字符串数组长度2,完成时间7

5. 测试字符串数组长度1

首次生成randomUUID耗时:278

非首次生成randomUUID 10000次耗时:71

String 拼接测试,测试长度10000,测试字符串数组长度1,完成时间1

String 使用循环 拼接测试,测试长度10000,测试字符串数组长度1,完成时间8

String.concat 拼接测试,测试长度10000,测试字符串数组长度1,完成时间3

StringBuilder 拼接测试,测试长度10000,测试字符串数组长度1,完成时间4

到此,可以看出,绝大多数情况下StringBuilder妥妥的比String 使用循环快,但是跟String直接相加差不多,String concat效率跟StringBuilder差不多,很多时候还要快一些,这些都是为什么呢?

javap -c StringTest.class 看看Java编译器都做了什么:

Compiled from "StringTest.java"

public classStringTest {publicStringTest();

Code:0: aload_01: invokespecial #1 //Method java/lang/Object."":()V

4: return

public static voidmain(java.lang.String[]);

Code:0: sipush 10000

3: istore_14: iconst_25: anewarray #2 //class java/lang/String

8: astore_29: ldc #3 //String

11: astore_312: new #4 //class java/util/Date

15: dup16: invokespecial #5 //Method java/util/Date."":()V

19: astore 4

21: invokestatic #6 //Method java/util/UUID.randomUUID:()Ljava/util/UUID;

24: invokevirtual #7 //Method java/util/UUID.toString:()Ljava/lang/String;

27: astore 5

29: getstatic #8 //Field java/lang/System.out:Ljava/io/PrintStream;

32: new #9 //class java/lang/StringBuilder

35: dup36: invokespecial #10 //Method java/lang/StringBuilder."":()V

39: ldc #11 //String 首次生成randomUUID耗时:

41: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

44: new #4 //class java/util/Date

47: dup48: invokespecial #5 //Method java/util/Date."":()V

51: invokevirtual #13 //Method java/util/Date.getTime:()J

54: aload 4

56: invokevirtual #13 //Method java/util/Date.getTime:()J

59: lsub60: invokevirtual #14 //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;

63: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

66: invokevirtual #16 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

69: new #4 //class java/util/Date

72: dup73: invokespecial #5 //Method java/util/Date."":()V

76: astore 4

78: iconst_079: istore 6

81: iload 6

83: iload_184: if_icmpge 101

87: invokestatic #6 //Method java/util/UUID.randomUUID:()Ljava/util/UUID;

90: invokevirtual #7 //Method java/util/UUID.toString:()Ljava/lang/String;

93: astore 5

95: iinc 6, 1

98: goto 81

101: getstatic #8 //Field java/lang/System.out:Ljava/io/PrintStream;

104: new #9 //class java/lang/StringBuilder

107: dup108: invokespecial #10 //Method java/lang/StringBuilder."":()V

111: ldc #17 //String 非首次生成randomUUID

113: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

116: iload_1117: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

120: ldc #19 //String 次耗时:

122: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

125: new #4 //class java/util/Date

128: dup129: invokespecial #5 //Method java/util/Date."":()V

132: invokevirtual #13 //Method java/util/Date.getTime:()J

135: aload 4

137: invokevirtual #13 //Method java/util/Date.getTime:()J

140: lsub141: invokevirtual #14 //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;

144: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

147: invokevirtual #16 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

150: new #4 //class java/util/Date

153: dup154: invokespecial #5 //Method java/util/Date."":()V

157: astore 4

159: iconst_0160: istore 6

162: iload 6

164: iload_1165: if_icmpge 195

168: new #9 //class java/lang/StringBuilder

171: dup172: invokespecial #10 //Method java/lang/StringBuilder."":()V

175: aload 5

177: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

180: aload 5

182: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

185: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

188: astore_3189: iinc 6, 1

192: goto 162

195: getstatic #8 //Field java/lang/System.out:Ljava/io/PrintStream;

198: new #9 //class java/lang/StringBuilder

201: dup202: invokespecial #10 //Method java/lang/StringBuilder."":()V

205: ldc #20 //String String 拼接测试,测试长度

207: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

210: iload_1211: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

214: ldc #21 //String ,测试字符串数组长度

216: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

219: aload_2220: arraylength221: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

224: ldc #22 //String ,完成时间

226: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

229: new #4 //class java/util/Date

232: dup233: invokespecial #5 //Method java/util/Date."":()V

236: invokevirtual #13 //Method java/util/Date.getTime:()J

239: aload 4

241: invokevirtual #13 //Method java/util/Date.getTime:()J

244: lsub245: invokevirtual #14 //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;

248: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

251: invokevirtual #16 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

254: new #4 //class java/util/Date

257: dup258: invokespecial #5 //Method java/util/Date."":()V

261: astore 4

263: iconst_0264: istore 6

266: iload 6

268: iload_1269: if_icmpge 317

272: ldc #3 //String

274: astore_3275: iconst_0276: istore 7

278: iload 7

280: aload_2281: arraylength282: if_icmpge 311

285: new #9 //class java/lang/StringBuilder

288: dup289: invokespecial #10 //Method java/lang/StringBuilder."":()V

292: aload_3293: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

296: aload 5

298: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

301: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

304: astore_3305: iinc 7, 1

308: goto 278

311: iinc 6, 1

314: goto 266

317: getstatic #8 //Field java/lang/System.out:Ljava/io/PrintStream;

320: new #9 //class java/lang/StringBuilder

323: dup324: invokespecial #10 //Method java/lang/StringBuilder."":()V

327: ldc #23 //String String 使用循环 拼接测试,测试长度

329: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

332: iload_1333: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

336: ldc #21 //String ,测试字符串数组长度

338: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

341: aload_2342: arraylength343: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

346: ldc #22 //String ,完成时间

348: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

351: new #4 //class java/util/Date

354: dup355: invokespecial #5 //Method java/util/Date."":()V

358: invokevirtual #13 //Method java/util/Date.getTime:()J

361: aload 4

363: invokevirtual #13 //Method java/util/Date.getTime:()J

366: lsub367: invokevirtual #14 //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;

370: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

373: invokevirtual #16 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

376: new #4 //class java/util/Date

379: dup380: invokespecial #5 //Method java/util/Date."":()V

383: astore 4

385: iconst_0386: istore 6

388: iload 6

390: iload_1391: if_icmpge 408

394: aload 5

396: aload 5

398: invokevirtual #24 //Method java/lang/String.concat:(Ljava/lang/String;)Ljava/lang/String;

401: astore_3402: iinc 6, 1

405: goto 388

408: getstatic #8 //Field java/lang/System.out:Ljava/io/PrintStream;

411: new #9 //class java/lang/StringBuilder

414: dup415: invokespecial #10 //Method java/lang/StringBuilder."":()V

418: ldc #25 //String String.concat 拼接测试,测试长度

420: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

423: iload_1424: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

427: ldc #21 //String ,测试字符串数组长度

429: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

432: aload_2433: arraylength434: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

437: ldc #22 //String ,完成时间

439: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

442: new #4 //class java/util/Date

445: dup446: invokespecial #5 //Method java/util/Date."":()V

449: invokevirtual #13 //Method java/util/Date.getTime:()J

452: aload 4

454: invokevirtual #13 //Method java/util/Date.getTime:()J

457: lsub458: invokevirtual #14 //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;

461: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

464: invokevirtual #16 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

467: new #4 //class java/util/Date

470: dup471: invokespecial #5 //Method java/util/Date."":()V

474: astore 4

476: iconst_0477: istore 7

479: iload 7

481: iload_1482: if_icmpge 533

485: ldc #3 //String

487: astore_3488: new #9 //class java/lang/StringBuilder

491: dup492: invokespecial #10 //Method java/lang/StringBuilder."":()V

495: astore 6

497: iconst_0498: istore 8

500: iload 8

502: aload_2503: arraylength504: if_icmpge 521

507: aload 6

509: aload 5

511: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

514: pop515: iinc 8, 1

518: goto 500

521: aload 6

523: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

526: astore_3527: iinc 7, 1

530: goto 479

533: getstatic #8 //Field java/lang/System.out:Ljava/io/PrintStream;

536: new #9 //class java/lang/StringBuilder

539: dup540: invokespecial #10 //Method java/lang/StringBuilder."":()V

543: ldc #26 //String StringBuilder 拼接测试,测试长度

545: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

548: iload_1549: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

552: ldc #21 //String ,测试字符串数组长度

554: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

557: aload_2558: arraylength559: invokevirtual #18 //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

562: ldc #22 //String ,完成时间

564: invokevirtual #12 //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

567: new #4 //class java/util/Date

570: dup571: invokespecial #5 //Method java/util/Date."":()V

574: invokevirtual #13 //Method java/util/Date.getTime:()J

577: aload 4

579: invokevirtual #13 //Method java/util/Date.getTime:()J

582: lsub583: invokevirtual #14 //Method java/lang/StringBuilder.append:(J)Ljava/lang/StringBuilder;

586: invokevirtual #15 //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

589: invokevirtual #16 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

592: return}

String直接相加已经都被编译器优化成StringBuilder了,只是循环里优化的不太合理。所以,String相加快还是StringBuilder快,其实只是StringBuilder调用方式对比。。。

String.concat为什么快?

看看jdk1.8里这个方法的源代码就知道了:

publicString concat(String str) {int otherLen =str.length();if (otherLen == 0) {return this;

}int len =value.length;char buf[] = Arrays.copyOf(value, len +otherLen);

str.getChars(buf, len);return new String(buf, true);

}

简单粗暴,直接Arrays.copyOf,直接内存复制,这根StringBuilder原理类似,但是它不用初始化StringBuilder对象,只是每次concat都会创建一个新的String对象,所以在有些情况下它比StringBuilder要快一点。

结论:简单场景里,直接用+好了,反正编译器默认会优化成StringBuilder,毕竟对一般人来说加号可读性高一点。但是在循环中使用或者是比较复杂的应用场景里,还是尽量自己直接用StringBuilder或String concat。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值