最近再看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>//方式1
String str = "";
for (int i = 0;i < 1000;i ++) {
str = str + s;
}
//方式2
StringBuilder 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;
}
上段程序只是参考,还需完善