一、需求
给定一个String对象,过滤掉除数字(字符'0'-'9')以外的其它字符。要求时间开销尽可能小。过滤函数的原型如下: String filter(String str);
二、代码测试
public static void main(String[] args) {
String str = "";
long begin = System.currentTimeMillis();
for(int i=0;i<1024*1024;i++) {
str = filter7("D186783E36B721651E8AF96AB1C4000B");
}
long end = System.currentTimeMillis();
System.out.println("测试用时:"+(end-begin));
System.out.println(str);
}
三、不同版本
/**
* 过滤方法-1-
* 测试用时:4328
* 运行结果:1867833672165189614000
* 注:这种方法效果是最差的,拼接字符串时 起码也要想到StringBuffer或StringBuilder
*/
public static String filter1(String str) {
String newStr = new String();
for(int i=0;i<str.length();i++) {
if(str.charAt(i) >= '0' && str.charAt(i) <= '9') {
newStr += str.charAt(i);
}
}
return newStr;
}
/**
* 过滤方法-2-
* 测试用时:1656
* 运行结果:1867833672165189614000
* 注:使用StringBuffer后效率明显提高了
*/
public static String filter2(String str) {
StringBuffer sb = new StringBuffer();
for(int i=0;i<str.length();i++) {
if(str.charAt(i) >= '0' && str.charAt(i) <= '9') {
sb.append(str.charAt(i));
}
}
return sb.toString();
}
/**
* 过滤方法-3-
* 测试用时:625
* 运行结果:1867833672165189614000
* 注:使用StringBuilder后效率也有不错的提升,因为StringBuffer是线程安全的它的方法都是同步的,
* 因此调用他的方法有一定的同步开销
*/
public static String filter3(String str) {
StringBuilder sb = new StringBuilder();
for(int i=0;i<str.length();i++) {
if(str.charAt(i) >= '0' && str.charAt(i) <= '9') {
sb.append(str.charAt(i));
}
}
return sb.toString();
}
/**
* 过滤方法-4-
* 测试用时:625
* 运行结果:1867833672165189614000
* 注:循环时就不必每次都计算一下传入的字符串的长度了,但是发现效率没有提升,可能是jdk自己做了优化
*/
public static String filter4(String str) {
StringBuilder sb = new StringBuilder();
int length = str.length();
for(int i=0;i<length;i++) {
if(str.charAt(i) >= '0' && str.charAt(i) <= '9') {
sb.append(str.charAt(i));
}
}
return sb.toString();
}
/**
* 过滤方法-5-
* 测试用时:594
* 运行结果:1867833672165189614000
* 注:通过StringBuilder的构造函数设置初始的容量大小,可以有效避免append()追加字符时重新分配内存,从而提高性能.
*/
public static String filter5(String str) {
int length = str.length();
StringBuilder sb = new StringBuilder(length);
for(int i=0;i<length;i++) {
if(str.charAt(i) >= '0' && str.charAt(i) <= '9') {
sb.append(str.charAt(i));
}
}
return sb.toString();
}
/**
* 过滤方法-6-
* 测试用时:562
* 运行结果:1867833672165189614000
* 注:少了个str.charAt(i)提升效果不明显
*/
public static String filter6(String str) {
int length = str.length();
StringBuilder sb = new StringBuilder(length);
for(int i=0;i<length;i++) {
char ch = str.charAt(i);
if(ch >= '0' && ch <= '9') {
sb.append(ch);
}
}
return sb.toString();
}
/**
* 过滤方法-7-
* 测试用时:406
* 运行结果:1867833672165189614000
* 注:相比filter6 7里面有字符数组创建的开销, 而StringBuilder也有字符数组创建的开销.
* 二者差别就在于7少了StringBuilder对象创建的开销
*/
public static String filter7(String str) {
int length = str.length();
char[] chArray = new char[length];
int index = 0;
for(int i=0;i<length;i++) {
char ch = str.charAt(i);
if(ch >= '0' && ch <= '9') {
chArray[index] = ch;
index++;
}
}
return new String(chArray,0,index);
}
四、补充
版本6和版本7使用了空间换时间的手法来提升性能。假如被过滤的字符串很大,并且数字字符的比例很低,这种方式就不太合算了。
举个例子:被处理的字符串中,绝大部分都只含有不到10%的数字字符,只有少数字符串包含较多的数字字符。这时候该怎么办捏?对于filter6来说,可以把new StringBuffer(nLen);修改为new StringBuffer(nLen/10);来节约空间开销。但是filter7就没法这么玩了。
所以,具体该用版本6还是版本7,要看具体情况了。只有在你非常看重时间开销,且数字字符比例很高(至少大于50%)的情况下,用filter7才合算。否则的话,建议用filter6。
本文介绍了一种快速过滤字符串中非数字字符的方法,并对比了不同实现方式的性能。通过对多种方法的测试,得出使用字符数组结合StringBuilder进行过滤的效果最佳。
1626

被折叠的 条评论
为什么被折叠?



