Differences among String, StringBuilder and StringBuffer
Know what it is and why. We want to answer the basic characteristics of String.
String
- String is Java A class under Lang package
- Modified by the final keyword and cannot be inherited
- The internal data structure of JDK8 is char[] value modified by final, and JDK9 is Byte[] value array;
- Its modification and addition operations will lead to the creation of a new string object in the string constant pool in the heap;
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { //JDK8 uses string array to store values; private final char value[]; private int hash; // Default to 0
String depth description
public static void main(String[] args) { String s="123456"; System.out.println("vlaue="+s); s="abcde"; }
- Execute s = "123456";
s refers to "123456" in the string constant pool; - Execute s = "abcde"
Due to the immutability of String, the JVM will create a memory to store the new String in the String constant pool, and then store the new String in it. s points to the memory address of the new String;
- Is String really immutable?
//Create the string "Hello World" and assign it to the reference s String s = "Hello World"; System.out.println("s = " + s); //Gets the value field in the String class Field valueFieldOfString = String.class.getDeclaredField("value"); //Change access to the value attribute valueFieldOfString.setAccessible(true); //Gets the value of the value attribute on the s object char[] value = (char[]) valueFieldOfString.get(s); //Change the fifth character in the array referenced by value value[5] = '_'; System.out.println("s = " + s);
Get the String array value attribute of String through reflection technology, and dynamically modify the value of String array, so as to modify the value of String.
StringBuilder and StringBuffer
- Are modified by the final keyword and cannot be inherited;
- The implementation principle is based on the modifiable char array, with a default size of 16
- Both inherit from AbstractStringBuilder
- StringBuffer thread safe, StringBuilder non thread safe
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence { static final long serialVersionUID = 4383685877147921099L; public StringBuilder() { super(16); } } public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence { static final long serialVersionUID = 3388685877147921107L; public StringBuffer() { super(16); } } abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count; //... }
When StringBuilder and StringBuffer are instantiated, the data is stored in the character array value of AbstractStringBuilder;
- StringBuffer source code: all its internal methods are decorated with synchronized to ensure thread safety, but StringBuilder does not.
// StringBuffer source code @Override public synchronized StringBuffer append(Object obj) { toStringCache = null; super.append(String.valueOf(obj)); return this; } @Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
Modification of both
StringBuffer stb = new StringBuffer (8).append("123456"); stb.append("78910");
First, create a character array with a length of 8, add "123456" to this array, and there are two remaining positions;
When appending ("78910"), the JVM first determines whether the capacity is sufficient. If not, it creates a memory with a larger capacity in the heap again, and then copies the original string array to the new memory. Of course, if the capacity is enough, you can put data into this array without opening up new memory space again.
Application scenario
- String
In business scenarios where the String content does not change frequently, the String class is preferred;
For example: constant declaration, a small number of string splicing operations, etc - StringBuffer
In a multithreaded environment, string operations (splicing, replacement, deletion, etc.) are performed frequently.
For example, XML parsing, HTTP parameter parsing and encapsulation. - StringBuilder
Frequently perform string operations (such as splicing, replacement, deletion, etc.) and run in a single threaded environment
For example, SQL statement assembly, JSON encapsulation, etc.
Exception,Error
What are exceptions and errors
- Exception usually refers to the possible exceptions of our program, which can be divided into checkable exceptions and runtime exceptions.
- You can check for exceptions that will be prompted when we write programs, such as IOException.
- Runtime exceptions will not be prompted when we write the program, but only appear during the running process, such as
RuntimeException,NullPointerException. - Error refers to system level errors, such as JVM crash, stack overflow, etc; For example, OutofMemoryError exception and StackOverflowError error error.
-Both Exception and Error inherit the Throwable class.
Exception handling principle
- Try to catch specific exceptions instead of general exceptions
Don't use Exception directly when catching exceptions in general. It's best to be specific to specific exceptions; - Don't swallow exceptions raw
After the exception is caught, no substantive processing is done. - Capture only the necessary code snippets
- Do not use exception handling blocks to control code flow
Why is the code in finally bound to execute?
When the JVM runs the bytecode file, the code in finally will be executed before return; This ensures that finally code blocks will be executed;
Procedure 1
public static void main(String[] args) throws IllegalAccessException { System.out.println(test10()); } private static int test10() { int i = 0; try{ i++; System.out.println("try block, i = "+i); return i; }catch(Exception e){ //NumberFormatException //Here are two questions: 1 Catch exceptions in general and use Exception directly //2. Abnormal endocytosis without substantive treatment; i++; System.out.println("catch block i = "+i); return i; }finally{ i++; System.out.println("finally block i = "+i); } } Operation results: try block, i = 1 finally block i = 2 1
- Why did the return value last print 1?
- Take a look at the decompiled code first
public static void main(String[] args) throws IllegalAccessException { System.out.println(test10()); } private static int test10() { int i = 0; int var2; try { ++i; System.out.println("try block, i = " + i); int var1 = i; return var1; } catch (Exception var6) { ++i; System.out.println("catch block i = " + i); var2 = i; } finally { ++i; System.out.println("finally block i = " + i); } return var2; }
A new variable var1 is used in try to store the value of variable i. The value of var1 is 1,
The finally code block is an operation on i, not var1, and the operation on i is after the var1 assignment of the try code block and before return, so the returned i value is actually the value of var1, which is actually 1, not 2;
Procedure 2
public static void main(String[] args) throws IllegalAccessException { System.out.println(test11()); } private static List test11() { List<String> list = new ArrayList<String>(); try{ list.add("step try"); System.out.println("try block"); return list; }catch(Exception e){ list.add("step catch"); System.out.println("catch block"); return list; }finally{ list.add("step finally"); System.out.println("finally block "); } } Operation results: try block finally block [step try, step finally]
- Why is there step finally in the last printed content?
The reference used by objects in Java, i.e. list, stores the memory address. Adding data to the list actually operates on the data in the memory address. The reference address of list will not change. - Take another look at the decompiled code
public static void main(String[] args) throws IllegalAccessException { System.out.println(test11()); } private static List test11() { ArrayList list = new ArrayList(); ArrayList var2; try { list.add("step try"); System.out.println("try block"); ArrayList var1 = list; return var1; } catch (Exception var6) { list.add("step catch"); System.out.println("catch block"); var2 = list; } finally { list.add("step finally"); System.out.println("finally block "); } return var2; }
The var1 variable stores the reference address. Therefore, the printed content will have step finanly content.