刚开始学习Java时,做为只会C语言的小白,就为其中的字符串操做而感到震撼。相比之下,C语言在字节数组中保存一个结尾的\0去表示字符串,想实现字符串拼接,还须要调用strcpy库函数或者本身手动去复制数组,很是麻烦,更别提其余复杂操做,而Java经过String类让字符串操做变得十分简单和方便。除此以外,还有stringbuilder等这些类的辅助,那么本文就从String,StringBuiler和StringBuffer的区别开始,去探讨Java中的字符串操做。html
Java 提供了 String 类来建立和操做字符串。在源码中能够看到,String类内部的实现也是一个字节数组,这个数组是final类型的,所以String是不可变的对象,每次在对String类进行改变的时候都会生成一个新的string对象,而后将指针指向新的string对象。java
和 String 类不一样的是,StringBuilder 类的对象可以被屡次的修改,而且不产生新的对象。这个特性的意义在于,若是咱们进行大量的字符串操做,使用String类就会产生很大的性能消耗,而StringBuilder就能够避免这个问题。正则表达式
StringBuffer 和StringBuiler之间的最大不一样在于 StringBuilder 的方法不是线程安全的。express
因为 StringBuilder 相较于 StringBuffer 有速度优点,因此多数状况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的状况下,则必须使用 StringBuffer 类。数组
操做类型 | 说明 | 是否可变 | 线程安全性 | 性能 |
---|---|---|---|---|
Java中的String | String 类中使用 final 关键字修饰字符数组来保存字符串 |
不可变 | 线程安全 | 低 |
Java中的StringBuffer | 字符串变量 | 可变 | 线程安全 | 通常 |
Java中的StringBuilder | 字符串变量 | 可变 | 线程不安全 | 通常 |
C/C++ 中的char* 操做 | char *是一个指针,能够 指向一个字符串数组 |
可变 | 不可知 | 高 |
C/C++中的char数组 | 用一个字符数组来保存字符串 | 不可变 | 不可知 | 高 |
C/C++中的String封装类 | string能够被当作是以字符 为元素的一种容器。 |
可变 | 并发读操做 是线程安全的 |
较高 |
@Test public void test() { int count = 100000; long startTime = System.currentTimeMillis(); String str = ""; for(int i = 0; i< count; i++){ str += i; } System.out.println("执行"+count+"次 String 耗时:"+ getRunTime(startTime)); startTime = System.currentTimeMillis(); StringBuilder stringBuilder = new StringBuilder(""); for (int i = 0; i < count; i++) { stringBuilder.append(i); } System.out.println("执行"+count+"次 StringBuilder 耗时:"+ getRunTime(startTime)); startTime = System.currentTimeMillis(); StringBuffer stringBuffer = new StringBuffer(""); for (int i = 0; i < count; i++) { stringBuffer.append(i); } System.out.println("执行"+count+"次 StringBuffer 耗时:"+ getRunTime(startTime)); }
执行100000次 String 耗时:32s 执行100000次 StringBuilder 耗时:2ms 执行100000次 StringBuffer 耗时:4ms
能够看到String类的性能远低于StringBuiler和StringBuffer,而StringBuiler在本次测试中比Stringbuffer提升了50%的性能安全
@Test public void test0(){ //邮政编码 String postCode = "[1-9]\\d{5}"; //区号-座机号码 String areaCode = "\\d{3}-\\d{8}|\\d{4}-\\d{7}"; //手机号码 String phone = "(?:13\\d|15\\d|18\\d)\\d{5}(\\d{3}|\\*{3})"; String text = "邮政编码:440834"+ "区号-座机号码: 020-12345678"+ "手机号:13536373839"+ "邮政编码:440833"+ "区号-座机号码: 010-12345678"+ "手机号:13536373739"; Pattern p = Pattern.compile(postCode); Matcher m = p.matcher(text); System.out.println("文本中包含邮政编码:"); while (m.find()){ System.out.println(m.group()); } p = Pattern.compile(areaCode); m= p.matcher(text); System.out.println("文本中包含区号-座机号码:"); while (m.find()){ System.out.println(m.group()); } p = Pattern.compile(phone); m= p.matcher(text); System.out.println("文本中包含手机号:"); while (m.find()){ System.out.println(m.group()); } }
文本中包含邮政编码: 440834 123456 135363 440833 123456 135363 文本中包含区号-座机号码: 020-12345678 010-12345678 文本中包含手机号: 13536373839 13536373739
通过测试和比较,能够看到Java中同为字符串操做,但因为背后实现的原理不一样,造成的性能差别也是十分巨大,相比之下,C/C++中的字符串操做性能更高。String类的性能远低于StringBuiler和StringBuffer,而StringBuiler比Stringbuffer的性能稍微高一点。对性能的探究,最终仍是要回到使用场景,能够总结得出,若是不涉及字符串操做,那么String类是首选,若是涉及的字符串操做没有线程安全问题,那么使用StringBuilder,若是涉及的字符串操做存在线程安全问题,那么使用StringBuffer并发