本文部分内容来自于《突破程序员基本功的16课》,《Java程序性能优化》
1、拼接
1.1直接量拼接、变量拼接、fianl变量拼接
上干货,fuck goods
- public class StringTest {
- public static void main(String[] args) {
- test();
- test2();
- test3();
- }
- /**
- * 直接量拼接,对于编译期就能确定的值,编译器会将值合并
- * String hw = "hello" + "world";反编译class
- * 我们将看到
- * String hw = "helloworld";
- *
- * 所以hw == helloWorld 输出true
- */
- public static void test(){
- String hw = "hello" + "world";
- String helloWolrd = "helloworld";
- p(hw == helloWolrd);
- }
- /**
- * hw在编译期并不能确定值,因为h是变量,JVM在运行期才能确定其值
- * 会在运行期时,进行字串拼接生成新的字串对象,反编译class后
- * String hw = new StringBuilder(h).append("world");
- *
- * 输出false
- */
- public static void test2(){
- String h = "hello";
- String hw = h + "world";
- String helloWolrd = "helloworld";
- p(hw == helloWolrd);
- }
- /**
- * String hw = h + "world";虽然包含变量 h 的运算,但是编译器
- * 对fianl变量在编译期能确定其值,会发生宏替换,即:h变量替换成其值"hello",
- * 然后编译器会对直接量字串直接合并
- * String hw = h + "world";在编译完后就变成了 String hw = "helloworld";
- *
- * 输出 true
- *
- */
- public static void test3(){
- final String h = "hello";
- String hw = h + "world";
- String helloWolrd = "helloworld";
- p(hw == helloWolrd);
- }
- private static void p(boolean flag){
- System.out.println(flag);
- }
- }
1.2StringBuilder 和StirngBuffer
jdk5tiger以前,对于字符串拼接,例如:String hw = h + "wolrd",会产生临时变量,占用大量内存空间,需要程序员将 "+" 拼接改写成 StringBuffer.append();
java5提供了一个新的类用于字符串拼接StringBuilder,和StringBuffer略有区别,StringBuffer的方法是同步的,StringBuilder是非同步的。另外,java5的编译器会将 "+" 的字串,编译成StringBuilder.append(),也就是说,String str = a + b + c +d;这样的写法是不存在效率问题的,编译器帮你干了。
如无线程安全的要求,应该选择StringBuilder。
注意,编译器不是万能的
- //这样的写法在运行期,在循环内将会产生大量的 StringBuilder对象的实例,效率低下
- String str = "";
- for(int i = 0;i < 100000;i++){
- str += i;
- }
- //应该改成下面的写法
- StringBuilder sb = new StringBuilder();
- for(int i = 0;i < 100000;i++){
- sb.append(i);
- }
另外:StringBuilder有一个属性:容量,看下面构造函数
- /**
- * Constructs a string builder with no characters in it and an
- * initial capacity of 16 characters.
- */
- public StringBuilder() {
- super(16);
- }
- /**
- * Constructs a string builder with no characters in it and an
- * initial capacity specified by the <code>capacity</code> argument.
- *
- * @param capacity the initial capacity.
- * @throws NegativeArraySizeException if the <code>capacity</code>
- * argument is less than <code>0</code>.
- */
- public StringBuilder(int capacity) {
- super(capacity);
- }
StringBuilder的底层实现是char[]存储字串值,属性容量就是这个char[]数组的长度,默认是16,调用 append()方法时候,会先检查 (原字串长度+append新串长度) > 容量,如果超出,则是数组扩容为 (原字串长度+append新串长度 + 1) *2
结论:
(1)String str = "a" + "b" + "c";这样的直接量拼接,JVM将其视为String str = "abc";
(2)final变量的使用,同样也是有效率的。
(3)含有变量的拼接字串,String str = h + "world",在JDK5以上,大多数是不需要程序员改成StringBuilder或者StringBuffer的,但是在某些情况下是需要程序员写成StringBuilder/StringBuffer
(4)如果是大字串,需要多次调用 append,最好指定StringBuider 的容量,就像这样new StirngBuilder(1024),指定容量不要太大也不要太小,最好能预知构建完字串的长度,实在不知道也可以先预估一下
2、截取字符串
- public static void main(String[] args) {
- List<String> list = new ArrayList<String>();
- for(int i = 0;i < 100000;i++){
- String bigString = new String(new char[20*1024*1024]);
- String subStr = bigString.substring(1, 5);
- list.add(subStr);
- System.out.println("第几次" + i);
- }
- /*
- *第几次0
- 第几次1
- 第几次2
- 第几次3
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
- at java.util.Arrays.copyOf(Arrays.java:2882)
- at java.lang.StringValue.from(StringValue.java:24)
- at java.lang.String.<init>(String.java:178)
- at StringTest.main(StringTest.java:9)
- */
- }
指定-Xmx10m时,JDK1.6 中,上面的代码就溢出了,因为substring(int,int)
看源码
- public String substring(int beginIndex, int endIndex) {
- if (beginIndex < 0) {
- throw new StringIndexOutOfBoundsException(beginIndex);
- }
- if (endIndex > count) {
- throw new StringIndexOutOfBoundsException(endIndex);
- }
- if (beginIndex > endIndex) {
- throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
- }
- return ((beginIndex == 0) && (endIndex == count)) ? this :
- new String(offset + beginIndex, endIndex - beginIndex, value);
- }
也就是说,String subStr = bigString.substring(1, 5);strStr的char[]属性值和bigString的char[]属性值是相同的,所以subStr所占的内存空间和bigString的内存空间也是相同的,虽然subString只能显示出几个字符 ,subStr这个实例的各属性值如下:
private final char value[] = bigString.value; private final int offset = 1; private final int count = 5; private int hash;
解决:
- String subStr = new String(bigString.substring(1, 5));
这样,就不会溢出了
还有一个解决办法,换成jdk7,则无此泄露点
结论:若是从大字串中截取出较小字串,应使用new String(bigString.substring(1, 5))构建新的字串
http://www.ibm.com/developerworks/cn/java/j-lo-optmizestring/#_ 表 _1._Java
相关推荐
在实际应用中,可能还需要考虑输入验证、错误处理以及优化性能等问题,例如,当输入的十六进制字符串长度不是偶数时的处理,或者大量数据转换时的效率问题。 总结来说,LabVIEW中的十六进制字符串到普通字符串的...
|PowerBuilder 数组字符串相互转化 天津 李华锋 * * | | * *PowerBuilder 数组字符串相互转化 完全免费 * ...|老数组转字符串212863 | |新数组转字符串187 * |以上是200000个数组测试结果 | |优化效率相当明显
对于大量字符串转换,优化转换过程至关重要。可以使用缓冲区减少内存访问次数,或者批量处理多个字符串以提高效率。 总结,西门子PLC中将字符串转换为实数是常见的操作,可以通过内置函数或自定义子程序实现。理解...
在PHP编程中,有时我们需要对过长的字符串进行截断,以便在有限的空间内展示关键信息,例如在网页上显示文章摘要...在给定的文件“截断字符串优化函数.php”中,很可能包含了上述讨论的一些实现,供开发者参考和使用。
例如,如果你有一个JSON字符串`'{"name": "John", "age": 30}'`,`JSON.parse()`可以将其转换为一个JavaScript对象`{name: "John", age: 30}`。这样,你就可以通过`.name`或`.age`来访问这些属性。 2. `JSON....
2. **十六进制转字符串**:相反的过程需要先使用“十六进制到整数”函数将十六进制字符串转换为十进制,再用“整数到字符串”函数将十进制数值转化为字符串。需要注意的是,这里的“整数到字符串”可能会产生一个以...
在编程领域,字符串翻转是一项常见的操作,它涉及到将一个字符串的字符顺序反转。这里我们将深入探讨两种实现方式:使用类库方法和栈数据结构。 首先,让我们关注使用类库方法进行字符串翻转。在Python中,有一个...
正确地进行日期与字符串之间的转换对于数据处理、查询优化等方面有着不可忽视的作用。本文档将详细介绍Oracle中日期与字符串转换的方式,并通过具体的示例来演示如何实现这些转换。 #### 二、日期格式与字符串格式 ...
在实际应用中,可能还需要考虑一些额外的问题,比如数据验证(确保输入的是有效的二进制字符串)、错误处理(处理除法溢出、负数等特殊情况)、性能优化(对于大量数据的快速转换)等。这些都是提高代码质量、可靠性...
在VB(Visual Basic)编程中,处理字符串是常见的任务之一,其中包括将一个长字符串拆分成多个子字符串。这个过程通常称为“字符串拆分”或“分隔字符串”。在这个主题中,我们将深入探讨VB中如何实现这一操作,以及...
### 字符串转日期知识点详解 #### 一、概述 在日常开发工作中,我们经常会遇到需要将日期格式的字符串转换为`Date`类型的情况。这种转换对于数据处理、时间比较等操作至关重要。本文将详细介绍如何在Java环境中...
在C#中,处理字符串时,我们经常需要从一个较大的字符串中提取出特定部分,比如位于两个已知字符串之间的子串。这在解析日志、处理配置文件或者从HTML源码中提取信息时非常常见。标题中的“字符串提取(获取两个字符...
此外,对于大型字符串,可能需要优化内存管理,避免一次性加载整个字符串。 通过上述方法,我们可以创建一个功能完备的小工具,帮助开发者快速进行二进制和十六进制字符串的相互转换。这不仅可以提高工作效率,也有...
【C#优化字符串操作】 1. **Convert.ToInt32 与 Int32.Parse的比较** - `Convert.ToInt32`方法在处理无法转换的字符串(如`null`)时,不会抛出异常,而是返回0。这可能导致潜在的逻辑错误,因为0可能是一个有效的...
在处理大量数据时,可能需要考虑内存效率和性能优化,例如使用`StringBuilder`而非多次使用`+`操作符(在某些语言中,这会导致不必要的字符串拷贝)。 此外,对于跨语言交互或底层系统编程,可能还会涉及到字符编码...
### VB中对字符串的处理及其扩展 在Visual Basic(简称VB)编程环境中,字符串操作是一项基本且重要的功能。本文将详细介绍VB中对于字符串处理的基本方法及其一些实用的扩展技巧。 #### 1. 基本字符串操作 ##### ...
综上所述,"统计字符串中子字符串出现的次数,并返回"这一功能涉及了C#中的字符串基础知识、字符串查找方法、循环与递归逻辑、正则表达式以及算法优化等多个方面。通过深入理解和实践这些知识点,可以更好地应对各种...
在LabVIEW中,字符串通常以文本框(String Control)或字符串常量(String Constant)的形式存在。当你需要对字符串进行操作,如删除空格,可以使用各种字符串函数来实现。以下是一些关键步骤和知识点: 1. **字符...
首先,让我们讨论浮点数转字符串的过程。在C语言中,这个过程通常通过`printf`系列函数的`%f`格式化选项来完成。但是,如果你需要自定义转换逻辑,例如为了控制精度或避免标准库的使用,你可以编写自己的函数。一个...
首先,我们来看标题提到的"int转二进制字符串的方法"。在C++中,最常用的方法是通过位运算和循环来实现。一个简单的思路是利用位移操作符(`和`>>`)以及与操作符(`&`)来检查每个二进制位。以下是一个基本的示例:...