Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Is StringBuilder faster than String?

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "is StringBuilder faster than String". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "is StringBuilder faster than String"?

Is StringBuilder faster than String? 1. StringBuilder is faster than String. What's the evidence?

Laozi code a shuttle, there is always someone babbling about so bad, then StringBuilder in the end that fast!

1.1 Stringlong startTime = System.currentTimeMillis ()

String str = ""

For (int I = 0; I

< 1000000; i++) { str += i; } System.out.println("String 耗时:" + (System.currentTimeMillis() - startTime) + "毫秒"); 1.2 StringBuilderlong startTime = System.currentTimeMillis(); StringBuilder str = new StringBuilder(); for (int i = 0; i < 1000000; i++) { str.append(i); } System.out.println("StringBuilder 耗时" + (System.currentTimeMillis() - startTime) + "毫秒"); 1.3 StringBufferlong startTime = System.currentTimeMillis(); StringBuffer str = new StringBuffer(); for (int i = 0; i < 1000000; i++) { str.append(i); } System.out.println("StringBuffer 耗时" + (System.currentTimeMillis() - startTime) + "毫秒"); 「综上」,分别使用了 String、StringBuilder、StringBuffer,做字符串链接操作(100个、1000个、1万个、10万个、100万个),记录每种方式的耗时。最终汇总图表如下; 从上图可以得出以下结论; String 字符串链接是耗时的,尤其数据量大的时候,简直没法使用了。 这是做实验,基本也不会有人这么干!StringBuilder、 StringBuffer,因为没有发生多线程竞争也就没有????锁升级,所以两个类耗时几乎相同,当然在单线程下更推荐使用 StringBuilder 。2. StringBuilder 比 String 快, 为什么?String str = ""; for (int i = 0; i < 10000; i++) { str += i; } 这段代码就是三种字符串拼接方式,最慢的一种。不是说这种+加的符号,会被优化成 StringBuilder 吗,那怎么还慢? 确实会被JVM编译期优化,但优化成什么样子了呢,先看下字节码指令;javap -c ApiTest.class 一看指令码,这不是在循环里(if_icmpgt)给我 new 了 StringBuilder 了吗,怎么还这么慢呢?再仔细看,其实你会发现,这new是在循环里吗呀,我们把这段代码写出来再看看; String str = ""; for (int i = 0; i < 10000; i++) { str = new StringBuilder().append(str).append(i).toString(); } 现在再看这段代码就很清晰了,所有的字符串链接操作,都需要实例化一次StringBuilder,所以非常耗时。「并且你可以验证,这样写代码耗时与字符串直接链接是一样的。」 所以把StringBuilder 提到上一层 for 循环外更快。 String 源码分析public final class String implements java.io.Serializable, Comparable, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; ... } 1. 初始化 在与 谢飞机 的面试题中,我们聊到了 String 初始化的问题,按照一般我们应用的频次上,能想到的只有直接赋值,String str = "abc";,但因为 String 的底层数据结构是数组char value[],所以它的初始化方式也会有很多跟数组相关的,如下; String str_01 = "abc"; System.out.println("默认方式:" + str_01); String str_02 = new String(new char[]{'a', 'b', 'c'}); System.out.println("char方式:" + str_02); String str_03 = new String(new int[]{0x61, 0x62, 0x63}, 0, 3); System.out.println("int方式:" + str_03); String str_04 = new String(new byte[]{0x61, 0x62, 0x63}); System.out.println("byte方式:" + str_04); 以上这些方式都可以初始化,并且最终的结果是一致的,abc。如果说初始化的方式没用让你感受到它是数据结构,那么str_01.charAt(0);呢,只要你往源码里一点,就会发现它是 O(1) 的时间复杂度从数组中获取元素,所以效率也是非常高,源码如下; public char charAt(int index) { if ((index < 0) || (index >

= value.length)) {

Throw new StringIndexOutOfBoundsException (index)

}

Return value [index]

} 2. Invariant (final)

After the string is created, it is immutable. The + plus sign connection operation you see is to create a new object to store the data, which can be seen through the source code.

Little Brother Fu & String is immutable

You can see from the source code that the classes of String and the methods used to store strings are decorated with final, that is, once created, these are immutable.

"give an example."

String str_01 = "abc"

String str_02 = "abc" + "def"

String str_03 = str_01 + "def"

Regardless of other circumstances, for program initialization. How many objects will be initialized by the above codes str_01, str_02, and str_03? In fact, this initialization of several objects from the side is to reflect the variability of the object.

Next, we decompile the above code and use the instruction code to see how many objects are created.

"decompilation"

Public void test_00 ()

Code:

0: ldc # 2 / / String abc

2: astore_1

3: ldc # 3 / / String abcdef

5: astore_2

6: new # 4 / / class java/lang/StringBuilder

9: dup

10: invokespecial # 5 / / Method java/lang/StringBuilder. "() V

13: aload_1

14: invokevirtual # 6 / / Method java/lang/StringBuilder.append: (Ljava/lang/String;) Ljava/lang/StringBuilder

17: ldc # 7 / / String def

19: invokevirtual # 6 / / Method java/lang/StringBuilder.append: (Ljava/lang/String;) Ljava/lang/StringBuilder

22: invokevirtual # 8 / / Method java/lang/StringBuilder.toString: () Ljava/lang/String

25: astore_3

26: return

Str_01 = "abc", script: 0: ldc, creates an object. Str_02 = "abc" + "def", script: 3: ldc / / String abcdef, thanks to the optimization of JVM compilation time, two strings are connected to create an object store. Str_03 = str_01 + "def", script: invokevirtual, this is different, it needs to concatenate two strings, will create StringBuilder objects, until the final toString: () operation, a total of three objects are created.

So, we see that the creation of a string cannot be modified, and the concatenation operation creates a new object.

3. Intern () 3.1 Classic topic String str_1 = new String ("ab")

String str_2 = new String ("ab")

String str_3 = "ab"

System.out.println (str_1 = = str_2)

System.out.println (str_1 = = str_2.intern ())

System.out.println (str_1.intern () = = str_2.intern ())

System.out.println (str_1 = = str_3)

System.out.println (str_1.intern () = = str_3)

This is a classic String string test, which may be a little dizzy at first glance. The answer is as follows

False

False

True

False

True 3.2Source Code Analysis

Did you feel a little bit after reading the answer? in fact, maybe you know the method intern (). Here's a look at its source code.

/ * *

* Returns a canonical representation for the string object.

*

* A pool of strings, initially empty, is maintained privately by the

* class {@ code String}.

*

* When the intern method is invoked, if the pool already contains a

* string equal to this {@ code String} object as determined by

* the {@ link # equals (Object)} method, then the string from the pool is

* returned. Otherwise, this {@ code String} object is added to the

* pool and a reference to this {@ code String} object is returned.

*

* It follows that for any two strings {@ code s} and {@ code t}

* {@ code s.intern () = = t.intern ()} is {@ code true}

* if and only if {@ code s.equals (t)} is {@ code true}.

*

* All literal strings and string-valued constant expressions are

* interned. String literals are defined in section 3.10.5 of the

* The Java ™Language Specification.

*

* @ return a string that has the same contents as this string, but is

* guaranteed to be from a pool of unique strings.

, /

Public native String intern ()

What does this code and comment mean?

"native", indicating that intern () is a local method, and the underlying layer invokes the functions written in the C++ language through JNI.

"\ openjdk8\ jdk\ src\ share\ native\ java\ lang\ String.c"

Java_java_lang_String_intern (JNIEnv * env, jobject this)

{

Return JVM_InternString (env, this)

}

Oop result = StringTable::intern (string, CHECK_NULL)

Oop StringTable::intern (Handle string_or_null, jchar* name

Int len, TRAPS) {

Unsigned int hashValue = java_lang_String::hash_string (name, len)

Int index = the_table ()-> hash_to_index (hashValue)

Oop string = the_table ()-> lookup (index, name, len, hashValue)

If (string! = NULL) return string

Return the_table ()-> basic_add (index, string_or_null, name, len

HashValue, CHECK_NULL)

}

The code block is a bit long and only part of the content is intercepted here. The source code can learn from the open source jdk code. Join: https://codeload.github.com/abhijangda/OpenJDK8/zip/masterC++ code is a bit like the data structure of HashMap's hash bucket + linked list, which is used to store strings, so if the hash value conflict is serious, it will cause the linked list to be too long. This has been introduced in our explanation of hashMap, you can look back at the HashMap source code StringTable is a fixed-length array of 1009 sizes, jdk1.6 is not adjustable, jdk1.7 can be set-XX:StringTableSize, adjust as needed. 3.3 problem diagram

Look at the picture and speak as follows

First of all, the basic type compares the value, and the reference type compares the address. In addition, equal compares the hash value. The addresses of the objects from the two new must be different, so it is false. Intern (), which pushes the value directly into the constant pool, so after both objects have done the intern () operation, the alignment is the value in the constant pool. Str_3 = "ab", assignment, the JVM compiler optimizes, does not recreate the object, but refers directly to the value in the constant pool. So str_1.intern () = = str_3, and the alignment result is true.

Understand this structure, there is no need to memorize to deal with the interview, let understand is really understand, the brain will follow the pleasure.

StringBuilder source code analysis 1. Initialize new StringBuilder ()

New StringBuilder (16)

New StringBuilder ("abc")

All of these methods can be initialized. You can either pass an initialization capacity or initialize a default string. Its source code is as follows

Public StringBuilder () {

Super (16)

}

AbstractStringBuilder (int capacity) {

Value = new char [capacity]

}

Take a closer look, this is initializing the array! It's like using ArrayList if you don't operate it.

two。 Add element stringBuilder.append ("a")

StringBuilder.append ("b")

StringBuilder.append ("c")

The operation of adding an element is very simple, just use append, so how does it store it in the array? does it need to be expanded?

2.1 entry method public AbstractStringBuilder append (String str) {

If (str = = null)

Return appendNull ()

Int len = str.length ()

EnsureCapacityInternal (count + len)

Str.getChars (0, len, value, count)

Count + = len

Return this

} this is public final class StringBuilder extends AbstractStringBuilder, and the parent class shares this method with StringBuffer. This includes capacity testing, element copying, and recording the number of count. 2.2 capacity expansion operation

"ensureCapacityInternal (count + len);"

/ * *

* This method has the same contract as ensureCapacity, but is

* never synchronized.

, /

Private void ensureCapacityInternal (int minimumCapacity) {

/ / overflow-conscious code

If (minimumCapacity-value.length > 0)

ExpandCapacity (minimumCapacity)

}

/ * *

* This implements the expansion semantics of ensureCapacity with no

* size check or synchronization.

, /

Void expandCapacity (int minimumCapacity) {

Int newCapacity = value.length * 2 + 2

If (newCapacity-minimumCapacity < 0)

NewCapacity = minimumCapacity

If (newCapacity < 0) {

If (minimumCapacity < 0) / / overflow

Throw new OutOfMemoryError ()

NewCapacity = Integer.MAX_VALUE

}

Value = Arrays.copyOf (value, newCapacity)

}

As mentioned above, StringBuilder, just like the principle of manipulating arrays, needs to test the capacity and expand the capacity as needed. The capacity of the expansion is n * 2 + 2, and the original elements are copied to the new array.

2.3 fill elements

"str.getChars (0, len, value, count);"

Public void getChars (int srcBegin, int srcEnd, char dst [], int dstBegin) {

/ /...

System.arraycopy (value, srcBegin, dst, dstBegin, srcEnd-srcBegin)

}

The way elements are added is based on the System.arraycopy copy operation, which is a local method.

2.4 toString ()

Since stringBuilder is an array, how is it converted into a string?

StringBuilder.toString ()

@ Override

Public String toString () {

/ / Create a copy, don't share the array

Return new String (value, 0, count)

}

In fact, when you need to use it as a String string, you use the constructor of String to pass an array for conversion, which was introduced when we explained String above.

StringBuffer source code analysis

The use and underlying implementation of StringBuffer and StringBuilder,API are basically the same, except that StringBuffer adds synchronized. Lock, so it is thread-safe. The source code is as follows

@ Override

Public synchronized StringBuffer append (String str) {

ToStringCache = null

Super.append (str)

Return this

}

So, isn't synchronized a heavyweight lock? what optimizations does JVM have for it?

In fact, in order to reduce the performance loss caused by acquiring and releasing locks, biased locks, lightweight locks and heavyweight locks are introduced to optimize, and it carries out a lock upgrade. (this picture is quoted from the Internet user: "leek leek". Excellent painting)

In addition, in most cases, locks. There is no competition and is basically held by a thread. Therefore, in order to avoid the performance loss caused by acquiring and releasing locks, lock upgrade is introduced and cannot be degraded after upgrade. Commonly used API sequence number method describes 1str.concat ("cde") string concatenation, replace + sign 2str.length () to get length 3isEmpty () to determine empty 4str.charAt (0) to get specified location element 5str.codePointAt (0) to get specified location element, and return ascii code value 6str.getBytes () to get byte [] 7str.equals ("abc") compare 8str.equalsIgnoreCase ("AbC") ignore case Compare 9str.startsWith ("a") start position value to judge 10str.endsWith ("c") end position value to judge 11str.indexOf ("b") to judge element position, start position 12str.lastIndexOf ("b") to judge element position, and end position 13str.substring (0,1) to intercept 14str.split (",") split Canonical 15str.replace ("a", "d"), replaceAll replacement 16str.toUpperCase () to uppercase 17str.toLowerCase () to lowercase 18str.toCharArray () to array 19String.format (str, "") format,% s,% c,% b,% d,% x,% o,% f,% a,% e,% g,% h,%%,% n,% tx20str.valueOf ("123") to string 21trim () format Go to the beginning and end of the space 22str.hashCode () to get the hash value thank you for your reading, the above is the content of "is StringBuilder faster than String?" after the study of this article, I believe you have a deeper understanding of the problem that StringBuilder is faster than String, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report