读书笔记--编写高质量代码:改善java程序的151个建议(四)String,StringBuilder,StringBuffer

读书笔记--编写高质量代码:改善java程序的151个建议(四)String,StringBuilder,StringBuffer

使用字符串字面量赋值更加高效。

Java为了避免在一个系统中大量产生String对象,于是就设计了一个字符串池(也有叫做字符串常量池),在字符串池中所容纳的都是String字符串对象。

String创建规则:创建一个字符串时,首先没有检查池中是否有字面值相等的字符串。

如果有,则不再创建,直接返回池中该对象的引用。

如果没有则创建之,然后放到池中,并返回新建对象的引用。

注释字符串操作时的位置

例如代码:

public class Client {
    public static void main(String[] args) {
        String str1 = 1+2+"apples";
        String str2 = "apples:"+1+2;
    }
}

str1=3apples,str2=apples:12

正确使用String、StringBuffer、StringBuilder

CharSequence接口有三个实现类与字符串有关:String、StringBuffer、StringBuilder,虽然他们都与字符串有关,但是其处理机制是不同的。

String类是不可改变的(immutable)量,也就是创建后就不能再修改了.即使想通过Sting提供的方法来尝试修改,也是要么创建一个新的字符串对象,要么返回自己。string的substring(0)时返回自己。

StringBuffer是一个可变字符序列,它与String一样,在内存中保存的都是一个有序的字符序列(char类型的数组),不同点是StringBuffer对戏那个的值是可改变的。例如append()方法。

StringBuilder与StringBuffer基本相同,都是可变字符序列,不同点是:StringBuffer是线程安全的,StringBuilder是线程不安全的,查看源码可以发现StringBuffer的方法前都有synchronized关键字,这也是StringBuffer在性能上远低于StringBuilder的原因。

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

三者的使用场景

_ 使用String类的场景 在字符串不经常变化的场景中可以使用String类,例如常量的声明,少量的变量运算等。 _ 使用StringBuffer类的场景 在频繁惊醒字符串的元算(如拼接、替换、删除等),并且运行在多线程的环境中,则可以考虑使用StringBuffer,例如XML的解析,HTTP参数解析和封装等。 _ 使用StringBuilder类的场景。 和StringBuffer类似,只是运行在单线程环境中。

自由选择字符串拼接方法

+方法拼接字符串

虽然编译器对字符串的加号做了优化,它会使用StringBuilder的append方法进行追加,其原理如下:

public class Client {
    public static void main(String[] args) {
        String str = "abc";
        //str = str+"d";
        str = new StringBuilder(str).append("d").toString();
    }
}

+方法每次操作都会创建一个StringBuilder对象,而且都会执行一次toString 这两个步骤比较耗时。

concat方法拼接字符串

concat的源代码如下:

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
}

整体上看就是一个数组拷贝,虽然在内存中的处理都是原子性操作,速度非常快,不过,最后的return语句表明每次concat操作都会创建一个String对象,这就是concat比较耗时操作。

append方法拼接字符串

StringBuilder的append方法直接有父类AbstractStringBuilder实现,其代码如下:

 public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
        int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
        expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
    }

整个append方法都在做字符数组处理,加长,然后数组拷贝,这些都是基本的数据处理,没有创建任何对象,所以速度最快了。

三者的实现方法不同,性能也就不同,但并不表示我们一定要使用StringBuilder,这是因为+非常符合我们的编码习惯,适合人类阅读,两个字符串拼接,就用加号连一下,这很正常,也很有号,在大多数情况下我们都可以使用加号操作,只有在系统性能临界到时候才可以考虑使用concat或者append方法。而且,很多时候系统的80%的性能是消耗在20%的代码上的,我们的精力应该更多的投入到算法和结构上。

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

这个没什么好说的,正则表达式是恶魔,威力巨大,但难以控制。

强烈建议使用UTF编码

不想项目出现乱码问题就使用UTF-8格式编码。

字符串排序

String的compareTo的排序实现是按照英文字母表的顺序,想排序中文的话推荐使用Collator类进行排序例如:

public class Client {
    public static void main(String[] args) {
        Comparator<Object> cmp=Collator.getInstance(java.util.Locale.CHINA);//其中getinstance为获得所需要的语言环境
        String []str={"张三","阿门","别赛男","神仙","逍遥"};
        Arrays.sort(str, cmp);
        for (int i = 0; i < str.length; i++) {
        System.out.println(str[i]);
        }
    }
}

Collator的一个缺点是对一些偏僻字支持不好,但是也能满足一般的需求了。

猜你喜欢

转载自blog.csdn.net/qq413041153/article/details/32312611