20191201-编写高质量代码:4-字符串

  1. 推荐使用String直接量赋值

推荐直接声明方式:

String str = "a"
 String str1 = "china";
 String str2 = "china";
 String str3 = new String("china");
 String str4 = str3.intern();

 System.out.println(str1 == str2);
 System.out.println(str1 == str3);
 System.out.println(str1 == str4);

上面程序的输出结果是:

true
false
true

Java为了避免在一个系统中大量产生String对象,于是设计了一个字符串池(也叫字符串常量池),在字符串池中所容纳的都是String字符串对象,它的创建机制是这样的:创建一个字符串时,检查池中是否有字面值相等的字符串,如果有,则不再创建,直接返回池中该对象的引用,若没有则创建之,然后放回池中,并返回新建对象的引用。

使用new创建字符串时,直接声明一个String对象是不检查字符串池的,也不会把对象放到池中。

intern()会检查当前的对象在对象池中是否有字面值相同的引用对象,如果有则返回池中对象,没有则放置到对象池中,并返回当前对象。

对象放到池中会不会产生线程安全问题?

String是一个不可变对象,这其中包含了两层意思:

  1. String类是final类,不可继承,不可能产生一个String的子类

  2. 在String类提供的所有方法中,如果String有返回值,就会新建一个String对象,不对原对象进行修改,保证了原对象是不可该改变的。

  3. 注意方法中传递的参数要求

String source = "好是好";
System.out.println(source.replaceAll(source,"是"));

String source1 = "$是$";
System.out.println(source.replaceAll(source1,"是"));

运行结果:

是
$是$

第一个替换成功了,第二个失败了。

 /* Note that backslashes ({@code \}) and dollar signs ({@code $}) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string; */
 public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }

可以使用replace方法替代,它是replaceAll的简化版。replaceAll传递的第一个参数是正则表达式。

  1. 正确使用String、StringBuffer、StringBuilder

String类是不可改变的量,即创建后就不能再修改了。

StringBuffer和StringBuilder都是可变字符序列,不同点是:StringBuffer是线程安全的,StringBuilder是线程不安全的。

在性能方面,由于String类的操作都是产生新的String对象,而StringBuilder和StringBuffer只是一个字符数组的再扩容而已,所以String类的操作要慢于StringBuilder和StringBuffer。

使用场景:

  1. String类:字符串不经常变化的场景,如常量的声明、少量的变量运算等

  2. StringBuffer类:频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程的环境中

  3. StringBuilder:频繁进行字符串的运算(如拼接、替换、删除等),并且运行在单线程的环境中

  4. 注意字符串的位置

System.out.println("apples"+1+2);
System.out.println(1+2+"apples");

输出为:

apples12
3apples

这源于Java对加号的处理机制:在使用加号进行计算的表达式中,只要遇到String字符串,则所有的数据都会转换为String类型进行拼接(如果是基本类型,直接拼接;如果是对象,调用toString方法的返回值然后进行拼接)。

  1. 自由选择字符串拼接方法
    对一个字符串进行拼接有三种方法:
  • 加号 ➕
  • concat方法
  • StringBuilder/StringBuffer的append方法

"+"拼接字符串,类似于如下代码:

str = new StringBuilder(str).append("c").toString();

它与纯粹使用StringBuilder的append方法不同:每次循环都会创建一个StringBuilder对象;每次执行完毕都要调用toString方法;因此执行时间最慢。

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);
}

其整体看上去就是一个数组拷贝,虽然在内存中的处理都是原子性操作,速度非常快,不过最后的return语句,每次concat操作都会新创建一个String对象,这是其速度慢下来的真正原因。

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方法都在做字符数组处理,加长,然后数组拷贝,这些都是基本的数据处理,没有新建任何对象,所以速度也就最快。

  1. 推荐在复杂字符串操作中使用正则表达式

  2. 强烈建议使用UTF编码

  3. 对字符串排序持一种宽容心态

《编写高质量代码:改善Java程序的151个建议》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值