本文部分内容来自于《突破程序员基本功的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);subStr的char[]属性值和bigString的char[]属性值是相同的,所以subStr所占的内存空间和bigString的内存空间也是相同的,虽然subStr只能显示出几个字符 ,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))构建新的字串,然而,这并不是最优的方案,最优方案参考:
Java 性能优化之 String 篇
相关推荐
api-ms-win-crt-string-l1-1-0
api-ms-win-core-string-l1-1-0.dll
001-glib-gdate-suppress-string-format-literal-warning.patch 001-glib-gdate-suppress-string-format-literal-warning.patch 001-glib-gdate-suppress-string-format-literal-warning.patch
3. **DBFReader.java**:这个类可能是用于读取DBF文件的,其中应该包含了处理编码和解析数值字段的代码。 4. **DBFHeader.java、DBFField.java、DBFBase.java、DBFException.java**:这些类可能分别代表DBF文件的...
StringReader的用法---马克-to-win java视频字符串输入流的介绍
python库。 资源全名:string_color-0.2.0-py3-none-any.whl
资源来自pypi官网。 资源全名:string_color-1.1.1-py3-none-any.whl
CSLFX-string-input-compare-outresult-03.CPP
### 3. 缓冲区溢出的成因 - **不安全的编程习惯**:C/C++等语言允许直接操作内存,程序员在处理字符串、数组等时,如果没有进行边界检查,容易导致溢出。 - **错误的函数使用**:如使用`strcpy`、`sprintf`等不安全...
- **使用安全的编程语言或库**:例如C++的`std::string`,或者使用具有自动内存管理和溢出防护的语言如Rust。 - **返回地址保护**:如采用非返回预测技术(如Canary),在栈上放置一个随机值,如果溢出发生,这个值...
资源分类:Python库 所属语言:Python 使用前提:需要解压 资源全名:string_comparison-1.0.2-py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
ember-string-fns 该插件为Ember模板和组件提供了字符串帮助器。 安装: ember install ember-string-fns 用法 string-last-index-of string-not-equals string-pad-end string-pad-start string-repeat ...
java文档String和StringTokenizer 马克-to-win java视频 字符串解析器
c语言入门 C语言_leetcode题解之08-string-to-integer-atoi.c