在Java中连接字符串时是使用+号还是使用StringBuilder

跨马翻译工具核心技术解析与多场景应用测评 图片翻译技术通过OCR识别与机器翻译的融合,实现了视觉内容到目标语言的精准转换。其核心原理在于多模态信息处理,先提取图像中的文本特征,再结合语义分析进行跨语言转换。这类技术在跨境电商、学术研究、旅游等场景具有重要价值,能有效解决语言障碍带来的信息断层问题。以跨马翻译为代表的先进工具采用视觉-文本对齐算法,在保持原文排版的同时提升翻译准确率,其专业模式支持23个垂直领域术语库,实测手写体识别准确率达91%。对于开发者而言,通过API集成可实现批量图片翻译自动化,但需注意处理超小字号文本等现存技术瓶颈。 阅读详情

    字符串是Java程序中最常用的一种数据结构之一。在Java中的String类已经重载了"+"。也就是说,字符串可以直接使用"+"进行连接,如下面代码所示:

String s = "abc" + "ddd";


但这样做真的好吗?当然,这个问题不能简单地回答yes or no。要根据具体情况来定。在Java中提供了一个StringBuilder类(这个类只在J2SE5及以上版本提供,以前的版本使用StringBuffer类),这个类也可以起到"+"的作用。那么我们应该用哪个呢?

    下面让我们先看看如下的代码:

package string;
  
  
public class
 TestSimplePlus
  
{
      
public static void
 main(String[] args)
      
{
          String s 
= "abc"
;
          String ss 
= "ok" + s + "xyz" + 5
;
          System.out.println(ss);
      }

  }


上面的代码将会输出正确的结果。从表面上看,对字符串和整型使用"+"号并没有什么区别,但事实真的如此吗?下面让我们来看看这段代码的本质。
我们首先使用反编译工具(如jdk带的javap、或jad)将TestSimplePlus反编译成Java Byte Code,其中的奥秘就一目了然了。在本文将使用jad来反编译,命令如下:

jad -o -a -s d.java TestSimplePlus.class
 
反编译后的代码如下:

package string;

import
 java.io.PrintStream;

public class
 TestSimplePlus
{
    
public
 TestSimplePlus()
    
{
    
//
    0    0:aload_0         
    
//
    1    1:invokespecial   #8   <Method void Object()>
    
//    2    4:return          

    }


    
public static void main(String args[])
    
{
      String s 
= "abc"
;
    
//
    0    0:ldc1            #16  <String "abc">
    
//    1    2:astore_1        

      String ss = (new StringBuilder("ok")).append(s).append("xyz").append(5).toString();
    
//
    2    3:new             #18  <Class StringBuilder>
    
//
    3    6:dup             
    
//
    4    7:ldc1            #20  <String "ok">
    
//
    5    9:invokespecial   #22  <Method void StringBuilder(String)>
    
//
    6   12:aload_1         
    
//
    7   13:invokevirtual   #25  <Method StringBuilder StringBuilder.append(String)>
    
//
    8   16:ldc1            #29  <String "xyz">
    
//
    9   18:invokevirtual   #25  <Method StringBuilder StringBuilder.append(String)>
    
//
   10   21:iconst_5        
    
//
   11   22:invokevirtual   #31  <Method StringBuilder StringBuilder.append(int)>
    
//
   12   25:invokevirtual   #34  <Method String StringBuilder.toString()>
    
//   13   28:astore_2        

      System.out.println(ss);
    
//
   14   29:getstatic       #38  <Field PrintStream System.out>
    
//
   15   32:aload_2         
    
//
   16   33:invokevirtual   #44  <Method void PrintStream.println(String)>
    
//   17   36:return          

    }

}



读者可能看到上面的Java字节码感到迷糊,不过大家不必担心。本文的目的并不是讲解Java Byte Code,因此,并不用了解具体的字节码的含义。

使用jad反编译的好处之一就是可以同时生成字节码和源代码。这样可以进行对照研究。从上面的代码很容易看出,虽然在源程序中使用了"+",但在编译时仍然将"+"转换成StringBuilder。因此,我们可以得出结论,在Java中无论使用何种方式进行字符串连接,实际上都使用的是StringBuilder。
那么是不是可以根据这个结论推出使用"+"和StringBuilder的效果是一样的呢?这个要从两个方面的解释。如果从运行结果来解释,那么"+"和StringBuilder是完全等效的。但如果从运行效率和资源消耗方面看,那它们将存在很大的区别。

    当然,如果连接字符串行表达式很简单(如上面的顺序结构),那么"+"和StringBuilder基本是一样的,但如果结构比较复杂,如使用循环来连接字符串,那么产生的Java Byte Code就会有很大的区别。先让我们看看如下的代码:

package string;
  
  
import java.util.*
;
  
  
public class
 TestComplexPlus
  
{
      
public static void
 main(String[] args)
      
{
          String s 
= ""
;
          Random rand 
= new
 Random();
          
for (int i = 0; i < 10; i++
)
          
{
              s 
= s + rand.nextInt(1000) + " "
;
          }

          System.out.println(s);
      }

  }



上面的代码返编译后的Java Byte Code如下:

package string;

import
 java.io.PrintStream;
import
 java.util.Random;

public class
 TestComplexPlus
{

    
public
 TestComplexPlus()
    
{
    
//
    0    0:aload_0         
    
//
    1    1:invokespecial   #8   <Method void Object()>
    
//    2    4:return          

    }


    
public static void main(String args[])
    
{
        String s 
= ""
;
    
//
    0    0:ldc1            #16  <String "">
    
//    1    2:astore_1        

        Random rand = new Random();
    
//
    2    3:new             #18  <Class Random>
    
//
    3    6:dup             
    
//
    4    7:invokespecial   #20  <Method void Random()>
    
//    5   10:astore_2        

        for(int i = 0; i < 10; i++)
    
//
*   6   11:iconst_0        
    
//
*   7   12:istore_3        
    
//*   8   13:goto            49

         s = (new StringBuilder(String.valueOf(s))).append(rand.nextInt(1000)).append(" ").toString();
    
//
    9   16:new             #21  <Class StringBuilder>
    
//
   10   19:dup             
    
//
   11   20:aload_1         
    
//
   12   21:invokestatic    #23  <Method String String.valueOf(Object)>
    
//
   13   24:invokespecial   #29  <Method void StringBuilder(String)>
    
//
   14   27:aload_2         
    
//
   15   28:sipush          1000
    
//
   16   31:invokevirtual   #32  <Method int Random.nextInt(int)>
    
//
   17   34:invokevirtual   #36  <Method StringBuilder StringBuilder.append(int)>
    
//
   18   37:ldc1            #40  <String " ">
    
//
   19   39:invokevirtual   #42  <Method StringBuilder StringBuilder.append(String)>
    
//
   20   42:invokevirtual   #45  <Method String StringBuilder.toString()>
    
//
   21   45:astore_1        

    
//
   22   46:iinc            3  1
    
//
   23   49:iload_3         
    
//
   24   50:bipush          10
    
//   25   52:icmplt          16

        System.out.println(s);
    
//
   26   55:getstatic       #49  <Field PrintStream System.out>
    
//
   27   58:aload_1         
    
//
   28   59:invokevirtual   #55  <Method void PrintStream.println(String)>
    
//   29   62:return          

    }

}



大家可以看到,虽然编译器将"+"转换成了StringBuilder,但创建StringBuilder对象的位置却在for语句内部。这就意味着每执行一次循环,就会创建一个StringBuilder对象(对于本例来说,是创建了10个StringBuilder对象),虽然Java有垃圾回收器,但这个回收器的工作时间是不定的。如果不断产生这样的垃圾,那么仍然会占用大量的资源。解决这个问题的方法就是在程序中直接使用StringBuilder来连接字符串,代码如下:

package string;

import java.util.*
;

public class
 TestStringBuilder
{
    
public static void
 main(String[] args)
    
{
        String s 
= ""
;
        Random rand 
= new
 Random();
        StringBuilder result 
= new
 StringBuilder();
        
for (int i = 0; i < 10; i++
)
        
{
            result.append(rand.nextInt(
1000
));
            result.append(
" "
);
        }

        System.out.println(result.toString());
    }

}


上面代码反编译后的结果如下:
package string;

import
 java.io.PrintStream;
import
 java.util.Random;

public class
 TestStringBuilder
{

    
public
 TestStringBuilder()
    
{
    
//
    0    0:aload_0         
    
//
    1    1:invokespecial   #8   <Method void Object()>
    
//    2    4:return          

    }


    
public static void main(String args[])
    
{
        String s 
= ""
;
    
//
    0    0:ldc1            #16  <String "">
    
//    1    2:astore_1        

        Random rand = new Random();
    
//
    2    3:new             #18  <Class Random>
    
//
    3    6:dup             
    
//
    4    7:invokespecial   #20  <Method void Random()>
    
//    5   10:astore_2        

        StringBuilder result = new StringBuilder();
    
//
    6   11:new             #21  <Class StringBuilder>
    
//
    7   14:dup             
    
//
    8   15:invokespecial   #23  <Method void StringBuilder()>
    
//    9   18:astore_3        

        for(int i = 0; i < 10; i++)
    
//
*  10   19:iconst_0        
    
//
*  11   20:istore          4
    
//*  12   22:goto            47

        {
            result.append(rand.nextInt(
1000
));
    
//
   13   25:aload_3         
    
//
   14   26:aload_2         
    
//
   15   27:sipush          1000
    
//
   16   30:invokevirtual   #24  <Method int Random.nextInt(int)>
    
//
   17   33:invokevirtual   #28  <Method StringBuilder StringBuilder.append(int)>
    
//   18   36:pop             

            result.append(" ");
    
//
   19   37:aload_3         
    
//
   20   38:ldc1            #32  <String " ">
    
//
   21   40:invokevirtual   #34  <Method StringBuilder StringBuilder.append(String)>
    
//   22   43:pop             

        }


    
//   23   44:iinc            4  1
    
//
   24   47:iload           4
    
//
   25   49:bipush          10
    
//   26   51:icmplt          25

        System.out.println(result.toString());
    
//
   27   54:getstatic       #37  <Field PrintStream System.out>
    
//
   28   57:aload_3         
    
//
   29   58:invokevirtual   #43  <Method String StringBuilder.toString()>
    
//
   30   61:invokevirtual   #47  <Method void PrintStream.println(String)>
    
//   31   64:return          

    }

}



从上面的反编译结果可以看出,创建StringBuilder的代码被放在了for语句外。虽然这样处理在源程序中看起来复杂,但却换来了更高的效率,同时消耗的资源也更少了。
在使用StringBuilder时要注意,尽量不要"+"和StringBuilder混着用,否则会创建更多的StringBuilder对象,如在TestStringBuilder.java中的

for (int i = 0; i < 10; i++)
    
{
        result.append(rand.nextInt(
1000
));
        result.append(
" "
);
    }


改成如下形式:

for (int i = 0; i < 10; i++)
{
     result.append(rand.nextInt(
1000) + " "
);
}


则反编译后的结果如下:

... ...
   
for(int i = 0; i < 10; i++
)
  
//
*  10   19:iconst_0        
  
//
*  11   20:istore          4
  
//*  12   22:goto            65

   {
    result.append((
new StringBuilder(String.valueOf(rand.nextInt(1000)))).append(" "
).toString());
  
//
   13   25:aload_3         
  
//
   14   26:new             #21  <Class StringBuilder>
  
//   15   29:dup             

  ... ...

从上面的代码可以看出,Java编译器将"+"编译成了StringBuilder,这样for语句每循环一次,又创建了一个StringBuilder对象。
    如果将上面的代码在JDK1.4下编译,必须将StringBuilder改为StringBuffer,而JDK1.4将"+"转换为StringBuffer(因为JDK1.4并没有提供StringBuilder类)。StringBuffer和StringBuilder的功能基本一样,只是StringBuffer是线程安全的,而StringBuilder不是线程安全的。因此,StringBuilder的效率会更高。
 
 下面的代码是测试"+"和StringBuilder效率的代码:

 

public class thinking
{
    
private static void usePlus(int
 n)
    
{
        
long t =
 System.currentTimeMillis();
        String s 
= ""
;
        
for (int i = 0; i < n; i++
)
            s 
= s +
 i;
        System.out.println(s);
        System.out.println(
"+:"

                
+ String.valueOf(System.currentTimeMillis() - t));
    }

    
private static void useStringBuilder(int n)
    
{
        
long t =
 System.currentTimeMillis();
        StringBuilder str 
= new
 StringBuilder();
        
for (int i = 0; i < n; i++
)
            str.append(i);
        System.out.println(str.toString());
        System.out.println(
"StringBuilder:"

                
+ String.valueOf(System.currentTimeMillis() - t));
    }

    
public static void main(String[] args)
    
{
        useStringBuilder(
2000
);
        usePlus(
2000
);
    }

}


输出结果

01234567891011121314151617181920212 ... ...
StringBuilder:30
01234567891011121314151617181920212 ... ...
+:151

从上面的输出结果可以看出,使用StringBuilder的效率明显要比"+"高

 
注:此文可任意转载,但要注明作者和出处
河道水位标尺识别预警 yolov7 河道水位标尺识别预警系统通过python+yolov7网络模型技术,河道水位标尺识别预警算法对河道水位标尺进行实时监测,当河道水位出现异常情况时,河道水位标尺识别预警算法将自动发出警报提示后台管理人员及时采取措施。YOLO系列算法是一类典型的one-stage目标检测算法,其利用anchor box将分类与目标定位的回归问题结合起来,从而做到了高效、灵活和泛化性能好,所以在工业界也十分受欢迎。Yolo模型采用预定义预测区域的方法来完成目标检测,具体而言是将原始图像划分为 7x7=49 个网格(grid),每 阅读详情

相关推荐

用python提取PDF中各类文本内容的方法

用python提取PDF中各类文本内容的方法

安静的软件工程师 6086

String拼接也有用加号更好的时候

做String拼接时用StringBuilder(或StringBuffer)好还是直接用+号性能好?一般来说是前者,不过也有用加号略好的时候。首先我一直认为用+号有很好的可读性,而且当String拼接在一个等式时,即形如String s = “abc” + s2 + s3jdk的实现原理也是转换为一个StringBuilder并一直append,效率也是差不太多的,所以我是比较喜欢在无循环或条件...

weixin_30622181的博客 647

通达信强龙趋势幅图指标 - 精准捕捉趋势,把握强势行情,多角度分析个股,强弱一目了然

STICKLINE(趋势>0 AND SJTJ,4.8,5.8,1.5,0),COLORYELLOW;STICKLINE(资金>0 AND SJTJ,1.2,2.2,1.5,0),COLOR0080FF;STICKLINE(异动>0 AND SJTJ,0,1,1.5,0),COLORFF0080;STICKLINE(异动=0 AND SJTJ,0,1,1.5,1),COLORGRAY;

Q1809330692的博客 5633

什么情况下用“+”运算符进行字符串连接比调用StringBuffer/StringBuilder 对象的append方法连接字符串性能更好?

对于这个问题,分2种情况。 1.不涉及对象拼接,只有常量字符串的拼接 。如下: String s = “ab”+“cd”,JVM会直接处理成String s = “abcd”; 2.涉及到对象拼接。如下: String s = “ab”; String ss = s +“cd”; 细分为2种情况, ①:没有for循环。“+”与StringBuilder效果一样 ②:对于for循环。StringBuilber的对象写在循环外,减少对象的创建,性能比“+”好。具体如下: StringBuilber的对象写在循环

qq_41570705的博客 1006

《跨界杂谈》华为印象(五):高度集权的矩阵式架构

高度集权的矩阵式架构 “高度集权的矩阵式架构”不是官方术语。是笔者的一位同事非常经典的总结。解释这个句话还是有点困难的,笔者入职华为三年也没彻底搞明白,在这里只能尝试性的解释一下。 矩阵 我们先看一下“矩阵”。华为有两套部门职能体系,华为内部术语,叫实线部门和虚线部门。由实线与虚线部门交叉构成矩阵。大部分(但不是所有)华为员工都由两个部门(两个领导)进行管理。对员工而言,所谓的实线部

《云计算架构技术与实践》 2996

从零构建:如何在VSCode中为HBuilderX迁移的UniApp项目搭建TypeScript支持环境

本文详细指导如何将HBuilderX中的UniApp项目迁移至VSCode并搭建TypeScript支持环境。通过pnpm包管理器初始化项目、配置tsconfig.json和vite.config.ts文件,实现工程化迁移与TypeScript深度集成,提升开发效率和代码质量。

book8的博客 1050

java学习笔记--面试题

面试题 Intern()方法会把首次遇到的字符串实例复制到永久代中,返回的是永久代中这个字符串实例的引用。在jdk1.7中intern()实现不会再复制实例,只是在常量池中记录首次出现的实例。 数组没有length()方法。有length属性。String 有length()方法; 在最外层循环前添加一个标记A 使用break A;可以跳出多重循环。 instanceof可以检查参数是否为正确类...

qq_41024497的博客 331

opencv+nvcodec实现视频硬解码

最近遇到一个新项目,AI推理在上,为了方便和节省成本的考虑决定研究下模块。根据官网的说法显卡具有独立的和模块,所以理论上和是独立互不干涉的。以前的项目都只是把显卡当成推理工具,没有将它的功能利用起来,本身也是一种浪费。事实真的有这么丝滑吗?看到这里,如果你真的觉得是白叫的那就真的是了,事实究竟如何,请听我娓娓道来。NVCODEC全称是 NVIDIA VIDEO CODEC,是NVIDIA为绝大多数显卡配置的硬件编解码单元。不一定是所有显卡都有,一般来讲越新的显卡硬件编解码就越强,支持的格式也就越新。

jiexijihe945的博客 1万+

java 字符串拼接为什么要用 StringBuilder 而不直接用 String 相加连接

经常在网上看到或者在周围听到有人说字符串拼接不要直接用 String 相加, StringBuilder 的效率要比 String 直接相加拼接要高。还有人常说, StringBuffer 是同步的(线程安全的), StringBuilder 不是线程安全的,同步带来了性能消耗,那么 String 、 StringBuilder 、 StringBuffer 这三者的效率到底有多大的差距呢?

1万+

音频——DAC 性能测试

codec DAC 性能测试方法

tyustli 2235

Windows下Anaconda和PyTorch深度学习环境完整安装配置教程

本文详细介绍了在Windows系统下安装配置PyTorch深度学习环境的完整流程。主要内容包括:硬件环境检查(确认GPU支持)、Anaconda环境管理系统的安装与配置、虚拟环境的创建与管理方法、以及PyTorch及其相关组件的安装指南。特别强调了版本兼容性选择策略(如CUDA版本的确定)、显卡驱动更新、使用Anaconda创建隔离的PyTorch专用环境等关键步骤。无论是使用CPU还是GPU版本,读者都能按照教程快速搭建稳定的PyTorch开发环境,为深度学习项目打下坚实基础。

FJN110的博客 973

华为:什么情况下用“+”运算符进行字符串连接比调用 StringBuffer/StringBuilder 对象的 append 方法连接字符串性能更好?

字符串是 Java 程序中最常用的数据结构之一。在 Java 中 String 类已经重载了"+"。但这样做真的好吗?当然,这个问题不能简单地回答 yes or no。要根据具体情况来定。在 Java 中提供了一个StringBuilder 类(这个类只在 J2SE5 及以上版本提供,以前的版本使用 StringBuffer 类),这个类也可以起到"+"的作用。那么我们应该用哪个呢?上面的代码将会输出正确的结果。从表面上看,对字符串和整型使用"+"号并没有什么区别,但事实真的如此吗?

2401_83384536的博客 794

C# 工业视觉性能极致优化:多线程推理池 + 对象复用 + 批量检测,速度提升 10 倍实战

set;} // 输入图像set;} // 异步返回结果set;} // 用于监控延迟性能优化不是魔法,而是对资源生命周期的精细管理和对硬件特性的充分利用。多线程池解决了 CPU/GPU 闲置问题。对象池解决了 GC 停顿问题。零拷贝解决了总线带宽瓶颈。严格的 Dispose解决了内存泄漏问题。这套架构已在多个高速锂电、3C 电子检测产线落地,轻松应对 200ms 甚至 50ms 的严苛节拍。记住,在工业领域,稳定性与速度同等重要。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 304

在Java中连接字符串时是使用+号还是使用StringBuilder StringBuffer 加号

字符串是Java程序中最常用的一种数据结构之一。在Java中的String类已经重载的"+"。也就是说,字符串可以直接使用"+"进行连接,如下面代码所示: String s = "abc" + "ddd"; 但这样做真的好吗?当然,这个问题不能简单地回答yes or no。要根据具体情况来定。在Java中提供了一个StringBuilder类(这个类只在J2SE5及以上版本

qq897958555的博客 481

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

浅谈Java中连接字符串时使用"+"号和使用StringBuilder类的区别

主页君在留言板中看到有Javaer提出一个问题,就是Java里在连接字符串时,使用"+"号连接还是使用StringBuilder类(这个类只在J2SE5及以上版本提供,以前的版本使用StringBuffer类)连接。   为了解答这位Javaer的疑惑,可能也是许多人的疑惑,特此撰文来解答这个问题,同时也附上另外一个困扰很多Javaer的问题,就是"+"号和StringBuilder类连接字

1653

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Java中连接字符串时使用+号与使用StringBuilder的区别

字符串是Java程序中最常用的一种数据结构之一。在Java中的String类已经重载的”+”。也就是说,字符串可以直接使用”+”进行连接,如下面代码所示: String s = "abc" + "ddd";   但这样做真的好吗?当然,这个问题不能简单地回答yes orno。要根据具体情况来定。   在Java中提供了一个StringBuilder类(这个类只在J2SE5及以上版本提供,以前

Song's Blog 2071

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

上一篇: java面试笔试题大汇总
下一篇: 如何防止重载toString方法时产生递归调用
atomic_age
博客等级 码龄21年 14粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值