开发者

从java反编译及字节码角度探索分析String拼接字符串效率

开发者 https://www.devze.com 2023-12-12 10:37 出处:网络 作者: 红袖添香
目录前言拼接场景示例 1:示例 2:字节码信息总结前言 又刷到这篇文章 为什么idea建议去掉StringBuilder,使用“+”拼接字符串
目录
  • 前言
  • 拼接场景
    • 示例 1:
    • 示例 2:
    • 字节码信息
  • 总结

    前言

    又刷到这篇文章

    为什么idea建议去掉StringBuilder,使用“+”拼接字符串

    从java反编译及字节码角度探索分析String拼接字符串效率

    网上有很多文章用 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 stringBu编程客栈ilder = 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/lajsng/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.printhttp://www.devze.comln:(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    android             // int 100000
           8: if_icmpge     48
          11: new           #3                  // class java/lang/StringBuilder
          14: dup
          15: invokespecial #12                 // Meth编程客栈od 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拼接字符串效率的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号