一、前言

刚开始学习Java时,作为只会C语言的小白,就为其中的字符串操作而感到震撼。相比之下,C语言在字节数组中保存一个结尾的\0去表示字符串,想实现字符串拼接,还需要调用strcpy库函数或者自己手动去复制数组,非常麻烦,更别提其他复杂操作,而Java通过String类让字符串操作变得十分简单和方便。除此之外,还有stringbuilder等这些类的辅助,那么本文就从String,StringBuiler和StringBuffer的区别开始,去探讨Java中的字符串操作。

二、String,StringBuiler和StringBuffer

2.1 String类

Java 提供了 String 类来创建和操作字符串。在源码中可以看到,String类内部的实现也是一个字节数组,这个数组是final类型的,因此String是不可变的对象,每次在对String类进行改变的时候都会生成一个新的string对象,然后将指针指向新的string对象。

2.2 StringBuiler 类

和 String 类不同的是,StringBuilder 类的对象能够被多次的修改,并且不产生新的对象。这个特性的意义在于,如果我们进行大量的字符串操作,使用String类就会产生很大的性能消耗,而StringBuilder就可以避免这个问题。

2.3 StringBuffer 类

StringBuffer 和StringBuiler之间的最大不同在于 StringBuilder 的方法不是线程安全的

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

2.4 String,StringBuiler和StringBuffer的比较(对比C/C++)

操作类型 说明 是否可变 线程安全性 性能
Java中的String String 类中使用 final
关键字修饰字符数组来保存字符串
不可变 线程安全
Java中的StringBuffer 字符串变量 可变 线程安全 一般
Java中的StringBuilder 字符串变量 可变 线程不安全 一般
C/C++ 中的char* 操作 char *是一个指针,可以
指向一个字符串数组
可变 不可知
C/C++中的char数组 用一个字符数组来保存字符串 不可变 不可知
C/C++中的String封装类 string可以被看成是以字符
为元素的一种容器。
可变 并发读操作
是线程安全的
较高

三、各种字符串操作的效率测试

3.1 测试代码

    @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)); }

3.2 测试结果

执行100000次  String 耗时:32s
执行100000次 StringBuilder 耗时:2ms
执行100000次 StringBuffer 耗时:4ms

3.3 小结

可以看到String类的性能远低于StringBuiler和StringBuffer,而StringBuiler在本次测试中比Stringbuffer提高了50%的性能

四、Java字符串和正则表达式

4.1 测试代码

    @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());
}
}

4.2 测试结果

文本中包含邮政编码:
440834
123456
135363
440833
123456
135363
文本中包含区号-座机号码:
020-12345678
010-12345678
文本中包含手机号:
13536373839
13536373739

五、总结

经过测试和比较,可以看到Java中同为字符串操作,但由于背后实现的原理不同,形成的性能差异也是十分巨大,相比之下,C/C++中的字符串操作性能更高。String类的性能远低于StringBuiler和StringBuffer,而StringBuiler比Stringbuffer的性能稍微高一点。对性能的探究,最终还是要回到使用场景,可以总结得出,如果不涉及字符串操作,那么String类是首选,如果涉及的字符串操作没有线程安全问题,那么使用StringBuilder,如果涉及的字符串操作存在线程安全问题,那么使用StringBuffer

六、参考资料

Java中的字符串操作(比较String,StringBuiler和StringBuffer)的更多相关文章

  1. java入门学习笔记之2(Java中的字符串操作)

    因为对Python很熟悉,看着Java的各种字符串操作就不自觉的代入Python的实现方法上,于是就将Java实现方式与Python实现方式都写下来了. 先说一下总结,Java的字符串类String本 ...

  2. Java中的字符串驻留(String Interning)

    1. 首先String不属于8种基本数据类型,String是一个对象. 因为对象的默认值是null,所以String的默认值也是null:但它又是一种特殊的对象,有其它对象没有的一些特性. 2. ne ...

  3. JAVA中的字符串操作

    一.替换 1.把对应字符换成新的字符 比如"D:\java_learn"中的'\'换成‘\\’ String str = "D:\\java_learn\\JAVA学习\ ...

  4. Python中字符串操作函数string.split('str1')和string.join(ls)

    Python中的字符串操作函数split 和 join能够实现字符串和列表之间的简单转换, 使用 .split()可以将字符串中特定部分以多个字符的形式,存储成列表 def split(self, * ...

  5. JAVA中的时间操作

    java中的时间操作不外乎这四种情况: 1.获取当前时间 2.获取某个时间的某种格式 3.设置时间 4.时间的运算 好,下面就针对这四种情况,一个一个搞定. 一.获取当前时间 有两种方式可以获得,第一 ...

  6. java中的集合操作类(未完待续)

    申明: 实习生的肤浅理解,如发现有错误之处.还望大牛们多多指点 废话 事实上我写java的后台操作,我每次都会遇到一条语句:List<XXXXX> list = new ArrayList ...

  7. 转载:Java中的字符串常量池详细介绍

    引用自:http://blog.csdn.net/langhong8/article/details/50938041 这篇文章主要介绍了Java中的字符串常量池详细介绍,JVM为了减少字符串对象的重 ...

  8. 《Java入门第三季》第二章 认识 Java 中的字符串

    什么是 Java 中的字符串.1.在Java的世界里,字符串被作为String类型的对象处理. 2.通用的初始化的方式:String s = new String("i love you & ...

  9. 详解Java中的字符串

    字符串常量池详解 在深入学习字符串类之前, 我们先搞懂JVM是怎样处理新生字符串的. 当你知道字符串的初始化细节后, 再去写String s = "hello"或String s ...

随机推荐

  1. Tarjan算法(模板)

    算法思想: 首先要明确强连通图的概念,一个有向图中,任意两个点互相可以到达:什么是强连通分量?有向图的极大连通子图叫强连通分量. 给一个有向图,我们用Tarjan算法把这个图的子图(在这个子图内,任意 ...

  2. SpringCloud服务的注册发现--------Eureka实现高可用

    1,Eureka作为注册中心,掌管者服务治理的功能,十分重要,如果注册中心的服务一旦宕机,所有的服务就会挂了,为此,实现注册中心的集群(高可用)就显得十分必要了 2,Eureka 搭建集群 实现原理就 ...

  3. Lisp-02: 函数

    函数(functions) 在 Lisp 中,函数分两种:有名函数和匿名函数(lambda函数). 有名函数 defun 有名函数的标准定义格式为: (defun <name> (list ...

  4. 使用Putty + Xming 远程登录Linux显示图形化界面

    一般我们远程登录linux 服务器,都是使用非加密的 telnet 或者加密的 ssh.这些登录方式有一个特点:只能登录字符界面,不能运行那些带有GUI界面的程序. 有时候为了学习或者工作的需要,我们 ...

  5. jenkins集成sonarQube实现代码质量检查

    1.sonarQube的简介 SonarQube是一款自动化代码审查工具,用于检测代码中的错误.漏洞和代码异味.它可以与你现有的工作流集成,以支持跨项目分支和拉取请求的连续代码检查. 其工作流程如下: ...

  6. vue 跳转 同一路由不刷新问题解决

    vue跳转同一路径时,路由参数改变,但页面无法更新 问题原因 vue路由切换实际是组件间的切换,引用相同组件的时候,页面就无法更新 解决方案 方案1.watch监听路由参数变化,并重新渲染(谨慎选择) ...

  7. QT-day1 创建项目

  8. Thinkphp getLastSql函数用法

    如何判断一个更新操作是否成功: $Model = D('Blog'); $data['id'] = 10; $data['name'] = 'update name'; $result = $Mode ...

  9. MTK Android 回调机制[CallBack]

    具体步骤: 一.建模 回调函数的关键是:将一段代码作为参数传递,而这段代码将会在某个时刻被执行 我理解的接口回调就是,我这个类实现了一个接口里的方法doSomething,然后注册到你这里,然后我就去 ...

  10. Linux 磁盘管理篇(一 磁盘分区)

    显示系统所有分区内容            fdisk 分区工具                parted fdisk: 执行完后按下 q 是退出不保存操作的意思 执行完后按下 w 是执行操作的意思 ...