Java 字符串拼接
Posted 刘润森!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 字符串拼接相关的知识,希望对你有一定的参考价值。
前言
本文参考网上的一些博文,结合自身的开发经验,整理出一些字符串拼接的使用建议。
版本约定
- JDK 版本:1.8.0_231
- Java SE API Documentation:https://docs.oracle.com/javase/8/docs/api/
正文
字符串不变性与字符串拼接
,我们知道字符串是不可变的。所以字符串的拼接,都是重新生成一个新的字符串。比如下面这段字符串拼接代码。
public static void main(String[] args)
String s = "abcd";
s = s.concat("ef");
其实最后我们得到的 s 已经是一个新的字符串了。如下图:
s 中保存的是一个重新创建出来的 String 对象的引用。
符号 ‘+’
在 Java 中,拼接字符串最简单的方式就是直接使用符号 ‘+’ 来拼接。
public static void main(String[] args)
String message = "User's age: ";
int age = 18;
System.out.println(message + age);
运行程序,输出:
User's age: 18
‘+’ 号按照给定的次序将两个字符串拼接起来。我们注意到,当将一个字符串与一个非字符串的值进行拼接时,后者会被转换成字符串。
在 Java 中,任何一个 Java 对象都可以转换成字符串,默认会调用 Java 对象的 toString() 方法生成 Java 对象的字符串。
一些简单的场景,或者说是不涉及到遍历生成字符串的场景都可以使用符号 ‘+’ 来拼接字符串。
实现原理
符号 ‘+’ 是 Java 提供的语法糖,我们不知道它是怎么实现的。只能先把 .java 文件编译成 .class 文件,然后通过反编译工具 Jad 反编译生成的 .class 文件,查看字节码文件中真正的实现。
public static void main(String args[])
String message = "User's age: ";
int age = 18;
System.out.println((new StringBuilder()).append(message).append(age).toString());
如上所示,它是通过 StringBuilder 实现的。
concat
除了使用符号 ‘+’ 拼接字符串之外,还可以使用 String 类中 concat 方法来拼接字符串。
public static void main(String[] args)
String message = "User's age: ";
int age = 18;
System.out.println(message.concat(age + ""));
运行程序,输出:
User's age: 18
concat 方法的使用场景很少,一般用不到。
实现原理
我们通过 concat 的源码了解一下它的实现原理。
public String 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);
首先创建了一个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,并使用这个字符数组创建一个新的 String 对象并返回。
StringBuilder & StringBuffer
使用 StringBuilder 可以方便的对字符串进行拼接。
public static void main(String[] args)
String message = "User's age: ";
int age = 18;
StringBuilder sb = new StringBuilder();
sb.append(message).append(age);
System.out.println(sb.toString());
StringBuffer 的用法和 StringBuilder 类似,StringBuffer 是线程安全的,性能对比 StringBuilder,要差点,一般我们也不会使用。
实现原理
接下来我们看看 StringBuilder 和 StringBuffer 的实现原理。
StringBuilder 继承了 AbstractStringBuilder,和 String 类类似,AbstractStringBuilder 类也封装了一个字符数组,定义如下:
/**
* The value is used for character storage.
*/
char[] value;
与 String 不同的是,它并不是 final 的,所以它是可以修改的。另外,它还提供了一个实例变量,用来记录数组中已经使用的字符个数。
/**
* The count is the number of characters used.
*/
int count;
StringBuilder 的 append 方法重写了父类的方法,并且调用了父类的 append 方法。
@Override
public StringBuilder append(String str)
super.append(str);
return this;
AbstractStringBuilder 的 append 方法如下所示:
public AbstractStringBuilder append(String str)
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
append 方法内部还是通过字符数组拷贝实现的,如果字符数组长度不够,通过 ensureCapacityInternal 方法进行扩容。
StringBuffer 和 StringBuilder 类似,最大的区别就是 StringBuffer 是线程安全的,看一下 StringBuffer 的 append 方法。
@Override
public synchronized StringBuffer append(String str)
toStringCache = null;
super.append(str);
return this;
该方法使用 synchronized 进行声明,说明是一个线程安全的方法。而 StringBuilder 则不是线程安全的。
String.join
Java 8 的 String 类中提供了一个静态方法:join,使用方式如下。
public static void main(String[] args)
String message = String.join("-", "Java", "is", "cool");
System.out.println(message);
运行程序,输出:
Java-is-cool
该方法比较适合用来将字符串数组以固定的拼在这里插入代码片
接符拼接到一起形成新的字符串。
实现原理
通过查看 String.join 方法的源码,我们发现,它是通过 StringJoiner 类实现的。
public static String join(CharSequence delimiter, CharSequence... elements)
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// Number of elements not likely worth Arrays.stream overhead.
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs: elements)
joiner.add(cs);
return joiner.toString();
通过查看 StringJoiner 类的源码,它内部也是通过 StringBuilder 实现,受限于文章篇幅,这里就不列出来了。
StringJoiner 只是对 StringBuilder 的进一步封装,适合用来构造一个由固定分隔符分隔的字符序列,并且可以非常方便的添加前缀和后缀。
StringUtils.join
StringUtils 是 Apache Commons 中提供的字符串工具类,其中的静态方法 join 可以用来拼接字符串,用法和 String.join 方法类似。
public static void main(String[] args)
String[] arr = "Java", "is", "cool";
String message = StringUtils.join(arr, "-");
System.out.println(message);
总结
本文介绍了什么是字符串拼接,虽然字符串是不可变的,但是还是可以通过新建字符串的方式来进行字符串的拼接。
常用的字符串拼接方式有六种,分别是使用 ‘+’、concat、StringBuilder、StringBuffer、String.join 以及使用 StringUtils.join。
由于字符串拼接过程中会创建新的对象,所以如果要在一个循环体中进行字符串拼接,就要考虑内存问题和效率问题。
因此,经过对比,我们发现,直接使用 StringBuilder 的方式是效率最高的。因为 StringBuilder 天生就是设计来定义可变字符串和字符串的变化操作的。
但是,还要强调的是:
- 如果只是简单的字符串拼接,考虑直接使用 ‘+’ 即可;
- 如果是在 for 循环中进行字符串拼接,考虑使用 StringBuilder;
- 如果是通过一个 List 进行字符串拼接,则考虑使用 StringJoiner or String.join or StringUtils.join;
- 如果在并发场景中进行字符串拼接的话,要使用StringBuffer来代替StringBuilder。
以上是关于Java 字符串拼接的主要内容,如果未能解决你的问题,请参考以下文章