[每天一个技术点]:https://www.bilibili.com/video/BV17r4y1J7Wt/?spm_id_from=pageDriver
在Java 8源码中:将char数组进行了封装,使用String类型来表达字符串
public final class String{
private final char value[];
}
String为什么不可变?
String不可变不仅仅是因为字符数组被final修饰,因为被final修饰,只能代表它不能指向新的数组,又不能代表字符数组本身数组不能被改变。String真正不可变的原因是:字符数组还被private修饰,且并没有暴露和提供任何修改字符数组的方法,一些字符串操作都是返回新的String对象。获取其底层数组也都是复制一个新数组进行返回,原数组不受影响。并且String类型还被final修饰,代表其不可被继承,从而杜绝子类覆盖父类行为的可能。
StringBulider继承于AbstractStringBuilder
abstract class AbstractStringBuilder{
char[] value;
}
public final class StringBulider extends AbstractStringBuilder{
}
由于字符串数组没被private final修饰因此是可被访问且可变的,并且StringBuilder提供了许多方法来修改字符串。append()在原字符串后添加字符。(使用String拼接对象底层实现也是调用StringBulider的append()方法)
因此频繁操作字符串还是推荐使用StringBulider.
缺点:线程不安全
StringBuffer也是继承于AbstractStringBuilder,也是能对字符串进行修改
public final class StringBuffer extends AbstractStringBuilder{
@Override
public synchronized StringBuffer append(String str){
// 省去部分代码
return this;
}
@Override
public synchronized StringBuffer append(int offset,String str){
// 省去部分代码
return this;
}
//省去其他方法
}
由于append()方法使用synchronized修饰,保证了线程安全。虽然降低效率,但是StringBulider也仅仅比StringBuffer高10%到15%的效率,却要冒着线程不安全的风险。
类型 | 特点 | 使用场景 |
---|---|---|
String | 不可变,线程安全 | 操作量少 |
StringBulider | 可变,线程不安全 | 单线程 |
StringBuffer | 可变,线程安全 | 多线程 |
当使用StringBuilder
String[] names = {"A","B","C","D"};
StringBuilder sb = new StringBuilder();
for (String name:names){
sb.append(name).append(',');
}
System.out.println(sb); //A,B,C,D,
拼接出的结果:A,B,C,D, 最后方包含:,
String[] names = {"A","B","C","D"};
StringBuilder sb = new StringBuilder();
for (String name:names){
sb.append(name).append(',');
}
sb.delete(sb.length()-1,sb.length() );
System.out.println(sb); //A,B,C,D
可以在拼接后删除
String[] names = {"A","B","C","D"};
StringBuilder sb = new StringBuilder("[");
for (int i =0;i< names.length;i++){
sb.append(names[i]);
if(i != names.length -1){
sb.append(",");
}
}
sb.append("]");
System.out.println(sb); //[A,B,C,D]
也可以在拼接时判断,当我们想要添加字符串头和结尾时还需要另外拼接一下
StringJoiner是减少以上字符串拼接的麻烦事宜出现的
String[] names = {"A","B","C","D"};
StringJoiner sj = new StringJoiner(",");
for (String name:names){
sj.add(name);
}
System.out.println(sj); //A,B,C,D
仅仅需要设置分隔符号即可StringJoiner(“,”)
String[] names = {"A","B","C","D"};
StringJoiner sj = new StringJoiner(",","[","]");
for (String name:names){
sj.add(name);
}
System.out.println(sj); //[A,B,C,D]
设置字符串的头和尾,也仅仅需要添加两个参数即可StringJoiner(“,”,“[”,“]”)
Java标准库的一些拼接方法就用了StringJoiner:String的静态方法join和Stream流中的常用的joining操作
String [] names = {"A","B","C","D"};
String.join(",",names);
Arrays.stream(names).collect(Collections.jioning(","));