java性能优化之String字符串优化

来源:互联网 发布:如何保持精力充沛 知乎 编辑:程序博客网 时间:2024/06/05 03:58

最近再看java性能优化相关的东西,做一下相关的笔记,对里面所说到的知识点,做个整理和总结吧

1.String.subString()方法

public String substring(int start, int end) {        if (start == 0 && end == count) {            return this;        }        // NOTE last character not copied!        // Fast range check.        if (start >= 0 && start <= end && end <= count) {            return new String(offset + start, end - start, value);        }        throw startEndAndLength(start, end);    }

这是这个函数的具体源码实现,作用很简单就是截取从start开始,到end为止的字符串,但这个函数是存在内存泄漏的,原因就是因为new String(offset + start, end - start, value),它采用了String的这个构造函数:
String(int offset, int charCount, char[] chars) {        this.value = chars;        this.offset = offset;        this.count = charCount;    }

从这个构造函数,可以看出,虽然我们要截取的是start到end的字符串,但是它新构造出的string实际上是原始string的数据,相当于空间换时间,这样速度快但是空间比较浪费,仅仅是改变了offset和count而已,这样的话,当我们一个字符串很长,但截取的数据又很短的时候,会非常浪费,过多的使用可能会造成内存持续增长造成溢出。

为了避免这个问题,我们可以优化一下substring函数的使用,采用new String(str.substring(start,end))方式,我们可以看下String(String str)构造函数:
public String(String toCopy) {        value = (toCopy.value.length == toCopy.count)                ? toCopy.value                : Arrays.copyOfRange(toCopy.value, toCopy.offset, toCopy.offset + toCopy.length());        offset = 0;        count = value.length;    }

从这个构造函数可以看出,这次新生成的对象的数据就是start到end的实际数据,而不是整个原始字符串,它用了Arrays.copyOfRange(toCopy.value, toCopy.offset, toCopy.offset + toCopy.length())来实现,而且new String(str.substring(start,end)),会解除substring返回的有问题的对象的强引用,使它可以被gc,采用这种方式可以优化内存。
<span style="font-family: Arial, Helvetica, sans-serif;">2.字符串累加操作</span>
<span style="font-family: Arial, Helvetica, sans-serif;">我们常用的字符串操作大致有三种:加号,stringBuilder,stringBuffer</span>
关于加号,比如str1+str2+str3,由于java编译器会对这种操作进行优化,优化成new stringBuilder(str1).append(str2).append(str3),所以这种场景下,加号的效率和stringBuilder是一样的,但是在下面场景中,将会有所不同:
<span style="white-space:pre"></span>//方式1String str = "";for (int i = 0;i < 1000;i ++) {str = str + s;}//方式2StringBuilder sb = new StringBuilder();for (int i = 0;i < 1000;i ++) {sb.append(s);}

方式1将会产生1000个对象,方式2只会有一个对象,所以一般情况下字符串连接操作最好使用stringBuilder。
至于stringBuilder和stringBuffer的区别,只在于stringBuffer内部实现加了同步,是线程安全的,当然由于同步,stringBuffer要更耗系统资源。
3.字符串split函数
String的split函数,功能是强大的,但是效率比较低,java中有个stringtokenizer(string dilem)专门用来分割字符串,效率要高于split函数,此外还可以通过indexOf(),和substring()函数,自己实现split函数,如:
public String[] split(String src, String delim) {if (src == null) {return null;}String[] rst = new String[src.length()];int indict = 0;String tmp = src;int index = -1;while ((index = tmp.indexOf(delim)) != -1) {rst[indict] = tmp.substring(0, index);tmp = tmp.substring(index + 1);indict ++;}
<span style="white-space:pre"></span>rst[indict] = tmp;return rst;}
上段程序只是参考,还需完善

0 0
原创粉丝点击