最近在阅读java.lang下的源码,读到String时,忽然想起面试的时候曾经被人问过:都知道在大数据量状况下,使用String的split截取字符串效率很低,有想过用其余的方法替代吗?用什么替代?我当时的回答很斩钉截铁:没有。 java
google了一下,发现有2中替代方法,因而在这里我将对这三种方式进行测试。 面试
测试的软件环境为:Windows XP、eclipse、JDK1.6。 正则表达式
测试用例使用类ip形式的字符串,即3位一组,使用”.”间隔。数据分别使用:5组、10组、100组、1000组、10000组、100000组。 数组
实现
闲话不说,先上代码: app
- package test.java.lang.ref;
-
- import java.util.Random;
- import java.util.StringTokenizer;
-
- /**
- * String测试类
- * @author xiaori.Liu
- *
- */
- public class StringTest {
-
- public static void main(String args[]){
- String orginStr = getOriginStr(10);
-
- //////////////String.splic()表现//////////////////////////////////////////////
- System.out.println("使用String.splic()的切分字符串");
- long st1 = System.nanoTime();
- String [] result = orginStr.split("\\.");
- System.out.println("String.splic()截取字符串用时:" + (System.nanoTime()-st1));
- System.out.println("String.splic()截取字符串结果个数:" + result.length);
- System.out.println();
-
- //////////////StringTokenizer表现//////////////////////////////////////////////
- System.out.println("使用StringTokenizer的切分字符串");
- long st3 = System.nanoTime();
- StringTokenizer token=new StringTokenizer(orginStr,".");
- System.out.println("StringTokenizer截取字符串用时:"+(System.nanoTime()-st3));
- System.out.println("StringTokenizer截取字符串结果个数:" + token.countTokens());
- System.out.println();
-
- ////////////////////String.substring()表现//////////////////////////////////////////
-
-
- long st5 = System.nanoTime();
- int len = orginStr.lastIndexOf(".");
- System.out.println("使用String.substring()切分字符串");
- int k=0,count=0;
-
- for (int i = 0; i <= len; i++) {
- if(orginStr.substring(i, i+1).equals(".")){
- if(count==0){
- orginStr.substring(0, i);
- }else{
- orginStr.substring(k+1, i);
- if(i == len){
- orginStr.substring(len+1, orginStr.length());
- }
- }
- k=i;count++;
- }
- }
- System.out.println("String.substring()截取字符串用时"+(System.nanoTime()-st5));
- System.out.println("String.substring()截取字符串结果个数:" + (count + 1));
- }
-
- /**
- * 构造目标字符串
- * eg:10.123.12.154.154
- * @param len 目标字符串组数(每组由3个随机数组成)
- * @return
- */
- private static String getOriginStr(int len){
-
- StringBuffer sb = new StringBuffer();
- StringBuffer result = new StringBuffer();
- Random random = new Random();
- for(int i = 0; i < len; i++){
- sb.append(random.nextInt(9)).append(random.nextInt(9)).append(random.nextInt(9));
- result.append(sb.toString());
- sb.delete(0, sb.length());
- if(i != len-1)
- result.append(".");
- }
-
- return result.toString();
- }
- }
改变目标数据长度修改getOriginStr的len参数便可。 dom
5组测试数据结果以下图: eclipse
下面这张图对比了下,split耗时为substring和StringTokenizer耗时的倍数: 性能
好吧,我又花了点儿时间,作了几张图表来分析这3中方式的性能。 测试
首先来一张柱状图对比一下这5组数据截取所花费的时间: 大数据
从上图能够看出StringTokenizer的性能实在是太好了(对比另两种),几乎在图表中看不见它的身影。遥遥领先。substring花费的时间始终比split要少,可是耗时也在随着数据量的增长而增长。
下面3张折线图能够很明显看出split、substring、StringTokenizer3中实现随着数据量增长,耗时的趋势。
split是变化最大的,也就是数据量越大,截取所须要的时间增加越快。
substring则比split要平稳一点点,可是也在增加。
StringTokenizer则是表现最优秀的,基本上平稳,始终保持在5000ns一下。
结论
最终,StringTokenizer在截取字符串中效率最高,不论数据量大小,几乎持平。substring则要次之,数据量增长耗时也要随之增长。split则是表现最差劲的。
究其缘由,split的实现方式是采用正则表达式实现,因此其性能会比较低。至于正则表达式为什么低,还未去验证。split源码以下:
- public String[] split(String regex, int limit) {
- return Pattern.compile(regex).split(this, limit);
- }