从java反编译及字节码角度探索分析String拼接字符串效率
作者:红袖添香
这篇文章主要介绍了从java反编译及字节码角度探索分析String拼接字符串效率,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
前言
又刷到这篇文章
为什么idea建议去掉StringBuilder,使用“+”拼接字符串
网上有很多文章用 JUnit 进行测试验证,可以网上搜一下,这里不做赘述。今天我们从反编译和字节码的角度分析字符串拼接的时候底层到底做了什么
拼接场景
示例 1:
public class Hello2 { public static void main(String[] args) { } public void add1() { String a = "aaa" + "bbb" + "ccc"; String b = new StringBuilder("aaa").append("bbb").append("ccc").toString(); } }
反编译结果:
package com.noah.nowcoder; public class Hello2 { public static void main(String[] args) {} public void add1() { String a = "aaabbbccc"; String b = "aaa" + "bbb" + "ccc"; } }
Java 编译器优化(JDK 版本相关),编译结果可以直接看出, String a = "aaa" + "bbb" + "ccc" 执行效率更高;
示例 2:
public class Hello { public static void main(String[] args) { String str1 = ""; for (int i = 0; i < 100000; i++) { str1 += "-" + UUID.randomUUID().toString(); } System.out.println(str1); StringBuilder stringBuilder = new StringBuilder(); for(int i = 0; i < 100000; ++i) { stringBuilder.append("-").append(UUID.randomUUID().toString()); } System.out.println(stringBuilder.toString()); } }
反编译结果:
package com.noah.nowcoder; import java.util.UUID; public class Hello { public static void main(String[] args) { String str1 = ""; for (int i = 0; i < 100000; i++) str1 = str1 + "-" + UUID.randomUUID().toString(); System.out.println(str1); StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < 100000; j++) stringBuilder.append("-").append(UUID.randomUUID().toString()); System.out.println(stringBuilder.toString()); } }
这一步结果不明显
字节码信息
接下来,我们看一下字节码信息
Compiled from "Hello.java" public class com.noah.nowcoder.Hello { public com.noah.nowcoder.Hello(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: ldc #3 // int 100000 8: if_icmpge 46 11: new #4 // class java/lang/StringBuilder 14: dup 15: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 18: aload_1 19: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 22: ldc #7 // String - 24: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: invokestatic #8 // Method java/util/UUID.randomUUID:()Ljava/util/UUID; 30: invokevirtual #9 // Method java/util/UUID.toString:()Ljava/lang/String; 33: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 36: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 39: astore_1 40: iinc 2, 1 43: goto 5 46: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 49: aload_1 50: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 53: new #4 // class java/lang/StringBuilder 56: dup 57: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V 60: astore_2 61: iconst_0 62: istore_3 63: iload_3 64: ldc #3 // int 100000 66: if_icmpge 91 69: aload_2 70: ldc #7 // String - 72: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 75: invokestatic #8 // Method java/util/UUID.randomUUID:()Ljava/util/UUID; 78: invokevirtual #9 // Method java/util/UUID.toString:()Ljava/lang/String; 81: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 84: pop 85: iinc 3, 1 88: goto 63 91: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream; 94: aload_2 95: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 98: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 101: return }
注意:
15: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
调用了 StringBuilder 构造函数,初始化了一个 StringBuilder 对象(循环中初始化对象)
总结
根据字节码改写代码
public void add2() { String str1 = ""; for (int i = 0; i < 100000; i++) { str1 += "-" + UUID.randomUUID().toString(); } System.out.println(str1); } public void add3() { String str1 = ""; for (int i = 0; i < 100000; i++) { StringBuilder stringBuilder = new StringBuilder(); str1 = stringBuilder.append(str1).append("-").append(UUID.randomUUID().toString()).toString(); } System.out.println(str1); }
字节码文件:
public void add3(); Code: 0: ldc #10 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: ldc #11 // int 100000 8: if_icmpge 48 11: new #3 // class java/lang/StringBuilder 14: dup 15: invokespecial #12 // Method java/lang/StringBuilder."<init>":()V 18: astore_3 19: aload_3 20: aload_1 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: ldc #13 // String - 26: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 29: invokestatic #14 // Method java/util/UUID.randomUUID:()Ljava/util/UUID; 32: invokevirtual #15 // Method java/util/UUID.toString:()Ljava/lang/String; 35: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 38: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 41: astore_1 42: iinc 2, 1 45: goto 5 48: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream; 51: aload_1 52: invokevirtual #17 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 55: return
从字节码文件可以看出,add2() 和 add3() 基本上等价的。
所以循环中拼接字符串更高效的做法是将 StringBulider 放在循环外。
如下:
public static void main(String[] args) { StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < 100000; j++) stringBuilder.append("-").append(UUID.randomUUID().toString()); System.out.println(stringBuilder.toString()); }
以上就是从java反编译及字节码角度探索分析String拼接字符串效率的详细内容,更多关于java String拼接字符串效率的资料请关注脚本之家其它相关文章!