程序员人生 网站导航

java中的String不再纠结

栏目:php教程时间:2017-02-10 08:40:10

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!


    这两天在淘测试的文章里看到1篇关于java string的文章,谈到了StringBuilder和StringBuffer的使用效力的问题,然后发现自己疏忽了capacity这个概念。比如说下面的1段代码:

1        StringBuffer sf = new StringBuffer("");
2         sf.append("leeon");
3         System.out.println("length: "+sf.length());
4         System.out.println("capacity: "+sf.capacity());

    这个打印的结果就是

    length:5

    capacity:16

    length我们可以理解,那末capacity是甚么呢?

    

     JDK源码中给出的解释就是用来存储新插入的字符空间的容量,可见1个默许的容量就是16了,固然如果我们像下面这样的去重写上面的代码,就会得到不1样的结果。

1         StringBuffer sf = new StringBuffer("leeon");
2         System.out.println("length: "+sf.length());
3         System.out.println("capacity: "+sf.capacity());

     这次的结果就是

     length:5

    capacity:21

    缘由就是我们在构造sf的时候本身的value已是5了,再加上了新准备插入的初始化容量,也就是5+16.具体实现的细节是:

    

     ----------------------------------------------------------------------------------------------------------

     以上是背景知识,下面开始讨论如何从capacity这个特性动身来优化性能。再仔细浏览jdk源码中append方法的实现的时候会发现,每次调用append都要进行容量的检查,由于要确保StringBuffer足够的大才能装得下新添加的字符串。无妨再1起看下代码:

   

  

   当调用append的时候,首先会通过ensureCapacityInternal检查所需的容量,如果容量不足再调用expandCapacity进行扩容,可以看见扩容的方式是将现在的字符串大小增加1倍然后再加上2.如果容量依然不足,则直接扩大到所需的大小。我们发现扩大容量就是1个耗时的操作,虽然处理大量字符串的时候采取StringBuffer会比用String更加的提升性能,但是却依然存在可优化的耗时部份。

  其实StringBuffer和StringBuilder在初始化的时候是可以指定capacity的,如果有1个大概的预估,初始化1个比较适合的capacity,减少扩大容量的操作,效力就会有更大的提高。比以下面的测试代码,我们对一样的字符串操作5百万次,统计1下结果。

复制代码
 1         StringBuilder sb = new StringBuilder(10*5000000);
 2         StringBuffer sf = new StringBuffer(10*5000000);
 3         
 4         
 5         long start = System.currentTimeMillis();  
 6         for(int i = 0; i < 5000000; i++)
 7         {
 8             sb.append("1234567890");
 9         }
10         long end = System.currentTimeMillis();
11         System.out.println("the StringBuilder run time is "+(end -start)+" ms");
12         
13         start = System.currentTimeMillis();  
14         for(int i = 0; i < 5000000; i++)
15         {
16             sf.append("1234567890");
17         }
18         end = System.currentTimeMillis();
19         System.out.println("the StringBuffer run time is "+(end -start)+" ms");
复制代码

 上面的结果我没有求平均值,测试也只是在单线程下进行的,但是数据波动不大,大致可以看出1些变化,我们发现当恰当的初始化了StringBuffer后,他的性能已和未初始化的StringBuilder相当乃至超过了,这样我们就可以够在保持和原来StringBuilder相当效力的基础上有更好的安全性了。

  可以看到采取了初始化的容量,我们取得的性能提升要高于从SF切换到SB。

  淘测试总结的结论中有1个我很喜欢,援用1下

  “ 用好现有的类比引入新的类更重要。很多程序员在使用 StringBuffer 时是不指定其容量的(最少我见到的情况是这样),如果这样的习惯带入 StringBuilder 的使用中,你将只能取得 10 %左右的性能提升(不要忘了,你可要冒多线程的风险噢);但如果你使用指定容量的 StringBuffer ,你将马上取得 45% 左右的性能提升,乃至比不使用指定容量的 StirngBuilder 都快 30% 左右。”

  这个问题其实后续还值得讨论,现在我们看到都是单线程的情况,那末多线程情况下,StringBuffer是否是可以优化的更多了?

  忽然发现,自己疏忽了很多java的特性,学在当下。

学习Java的同学注意了!!! 
学习进程中遇到甚么问题或想获得学习资源的话,欢迎加入Java学习交换群,群号码:183993990  我们1起学Java!

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐