如何选择String
字符串String是Java编程中使用概率最高的变量,也许你觉得没有什么可讲的,随手拈来,然而字符串的处理却尤其需要我们的关注,因为大量的字符串实例的随意创建,给系统的效率带来了很大的问题。
比如下面我们来做一个测试,对比String类和StringBuffer的执行效率:
● String执行10000次累加
long start = System.currentTimeMillis();
String str = "";
for (int i = 0; i < 10000; i++) {
str += "," + i;
}
long end = System.currentTimeMillis();
System.out.println(end - start);
执行的结果花费了702ms。
● 使用StringBuffer类来代替String类:
long start = System.currentTimeMillis();
StringBuffer str = new StringBuffer();
for (int i = 0; i < 10000; i++) {
str.append(",").append(i);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
运行共花费了0ms。
通过对比发现StringBuffer几乎不花费时间。这是因为,String对象的每一次累加,都会先将累加的字符串创建一个实例对象然后再累加,等于是创建了10000个实例。而StringBuffer每次都是修改的原有实例对象,只是创建了1个实例。通过学习第2章我们已经知道,创建实例需要申请内存地址、写入数据的过程,大量的这种操作就会消耗大量的CPU计算资源。
也许你会说,StringBuffer这么高效率,那我们不再使用String类就可以了,然而实际情况是,它们在不同的情况下各有选择的优势。通过《高手真经 Java核心编程技术》第11.2节的讲解可知,String、StringBuffer与StringBuilder三者最大的区别是:
● String是字符串常量
● StringBuffer是字符串变量(线程安全)
● StringBuilder是字符串变量(非线程安全)
简要的说,String类型和StringBuffer类型的主要性能区别其实在于,String是不可变的对象,因此在每次对String类型进行改变的时候,其实都等同于生成了一个新的String对象,然后将指针指向新的String对象,所以经常改变内容的字符串最好不要用String,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后,JVM的GC就会开始工作,那速度是一定会相当慢的。
而如果是使用StringBuffer类则结果就不一样了,每次结果都会对StringBuffer对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用StringBuffer,特别是字符串对象经常改变的情况下。而在某些特别情况下,String对象的字符串拼接其实是被JVM解释成了StringBuffer对象的拼接,所以这些时候String对象的速度并不会比StringBuffer对象慢,而特别是以下的字符串对象生成中,String效率是远要比StringBuffer快的:
String str = “This is only a” + “ simple” + “ test”;
StringBuffer builder = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:
String str = “This is only a” + “ simple” + “test”;
其实就是:
String str = “This is only a simple test”;
所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:
String str2 = “This is only a”;
String str3 = “ simple”;
String str4 = “ test”;
String str1 = str2 +str3 + str4;
这时候JVM会规规矩矩的按照原来的方式去做。
为了测试这三个类的累加不同次数字符串时的效率,我们编写一个测试类,分别按次数累加字符串:
程序11-8 TestString.java
package test.String;
public class TestString {
static int count = 100;//循环次数
// 测试String
public static void testString() {
long start = System.nanoTime();
String str = "";
for (int i = 0; i < count; i++) {
str += "," + i;
}
long end = System.nanoTime();
System.out.println("String:" + (end - start));
}
// 测试StringBuffer
public static void testStringBuffer() {
long start = System.nanoTime();
StringBuffer str = new StringBuffer();
for (int i = 0; i < count; i++) {
str.append(",").append(i);
}
long end = System.nanoTime();
System.out.println("StringBuffer:" + (end - start));
}
// 测试StringBuilder
public static void testStringBuilder() {
long start = System.nanoTime();
StringBuilder str = new StringBuilder();
for (int i = 0; i < count; i++) {
str.append(",").append(i);
}
long end = System.nanoTime();
System.out.println("StringBuilder:" + (end - start));
}
public static void main(String[] args) {
TestString.testString();
TestString.testStringBuffer();
TestString.testStringBuilder();
}
}
运行该程序执行的测试时间:
表11-2 测试结果
毫微秒 |
String |
StringBuffer |
StringBuilder |
1次 |
69,562 |
46,934 |
8,101 |
10次 |
109,791 |
57,269 |
24,025 |
100次 |
431,619 |
172,089 |
128,228 |
1000次 |
8,274,236 |
876,368 |
270,985 |
1万次 |
704,425,841 |
2,673,524 |
1,388,166 |
10万次 |
溢出 |
20,926,961 |
11,669,361 |
100万次 |
溢出 |
246,871,041 |
137,586,760 |
String在10w次循环时就溢出了,而StringBuffer在100万次循环时间为246ms,StringBuilder的时间为137ms。显然选择优先级为:StringBuilder>StringBuffer>String。因此,对于这三个类的使用,我们需要按照以下情况去选择:
● 如果你偶尔对简单的字符串常量进行拼接,那么可以使用String,它足够简单而且轻量级;
● 如果你需要经常进行字符串的拼接、累加操作,请使用StringBuffer或StringBuilder;
● 如果是在单线程的环境中,建议使用StringBuilder,它要比StringBuffer快;如果是在多线程的环境中,建议使用StringBuffer,它是线程安全的;
因此,StringBuilder实际上是我们的首选,只有在多线程时才可以考虑使用StringBuffer,只有在字符串的拼接足够简单时才使用String。
本文出自《Java高手真经. 编程基础卷:Java核心编程技术:Java基础+核心库+图形+网络+高级特性》一书
转载于:https://www.cnblogs.com/haoxia/archive/2009/07/09/1519891.html
如何选择String相关推荐
- string类型比较_redis存json数据时选择string还是hash
我们在缓存json数据到redis时经常会面临是选择string类型还是选择hash类型去存储.接下来我从占用空间和IO两方面来分析这两种类型的优势. 1.占用空间 根据数据结构的共识我们知道hash ...
- String.valueOf()方法与toString()方法的区别
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 1. 两者都是把ObJect对象转化为String 类型. 2.string.valueof()方法 ...
- 一大波Java来袭(四)String类、StringBuilder类、StringBuffer类对照
本文主要介绍String类.StringBuffer类.StringBuilder类的差别 : 一.概述 (一)String 字符串常量.可是它具有不可变性,就是一旦创建,对它进行的不论什么改动操作 ...
- Android如何愉快的使用Spinner列表选择框
Android如何愉快的使用Spinner列表选择框 说实话 我刚学习的时候,感觉这就是网页上的select标签,不过,这个标签可以带图,哈哈 是不是感觉像 又到了我们粘贴代码的时间了 布局文件:ac ...
- Ionic2中的相册选择和拍照上传——ImgService
目录 目录 前言 Cordova准备 ImgService服务的实现 ImgService服务的使用 示例效果 相册选择器的汉化 参考 前言 在APP中启动相册选择器或者拍照上传图片这些功能是非常常见 ...
- ListView 选择模式
实际的应用APP开发中,基本上由自己来控制多选的逻辑,后来参考大神的作品,发现ListView本身已经实现了,下面就跟随我的足迹,一起探讨一下吧. ListView四种模式 /*** Normal l ...
- TVM apps extension示例扩展库
TVM apps extension示例扩展库 此文件夹包含TVM的示例扩展库.演示了其它库如何在C++和Python API中扩展TVM. 该库扩展了TVM的功能. python模块加载新的共享库, ...
- 记住密码以及Android 列表的操作
1.综合使用RecycleView,CardView,Adapter实现一个宝宝相册,并将其加入到实验一形成的应用中,使得:用户成功登录后转到宝宝相册所在的主界面.还要求实现:用户单击对应的列表子项的 ...
- 转载:Beginning WF 4.0翻译——第四章(传递参数)
在第一章,我已经向你展示了在工作流中怎么使用variables(变量)和arguments(参数).跟编码类似,variables类似于类成员,而arguments类似于方法的参数.你已经在前三章使用 ...
最新文章
- java字符串转换成日期型对象
- 为什么 Python被Google选为TensorFlow的开发语言呢?使用 Python比C++语言进行机器学习有什么优势?
- linux重命名的命令行操作,Linux rename命令批量重命名的方法
- 我的同事Leo做的一个AR增强现实的项目
- Struts01---入门小案例
- Java中的硬件事务性内存,或者为什么同步将再次变得很棒
- android 模糊查询控件_第三十二篇:在SOUI2.0中像android一样使用资源
- 关于负载均衡的几个问题
- cad页面布局快捷键_炸裂“图纸集”功能、高手都在偷偷用的CAD图纸管理神器
- Python-装饰器进阶
- 登录界面实现记住密码功能
- 信息系统项目管理师(2022年) —— 第 1 章 信息化和信息系统
- Report Machine(RM)报表控件简单用法-delphi
- 漫谈工业软件(2)-IEC61499标准
- 推荐12个免费查找文献的学术网站,建议点赞、收藏!
- HL7解析类的使用(java)
- Shiro(一)之shiro简介与工作原理
- 浅谈SAP FICO—总账科目
- 录屏软件Camtasia9的录屏文件存储位置/好用的免费录屏软件代替
- ArcGIS图像配准技巧:配准获取中国气候区分布数据(附练习数据下载)
热门文章
- 通话录音_iOS14,通话录音终于来了!
- hibernate-jpa/hibernate-jpa-2.1-api-1.0.0.final.jar源代码下载地址
- 极客时间《玩转Git三剑客》之GItHub剑客
- C++ : 二进制法生成子集
- 面向对象回顾(构造函数、覆盖和重载、Query接口的list方法和iterate方法、面向对象的六原则一法则、反射、内部类)
- python 安装包时出现红字_Python从入门到就业-1.1节:安装Python
- 反问疑问_句子练习大全(反问、疑问、设问、病句等练习)
- linux socket API / bind
- nfs上安装oracle,使用NFS安装oracle软件
- python gpiozero,树莓派远程GPIO调试(Python + pigpio版)