深入學習java原始碼之下StringBuilder類append方法
深入學習java原始碼之下StringBuilder類append方法
StringBuilder的append方法
StringBuilder sb = new StirngBuilder();
sb.append("a").append("b").append("c").append("d");
String str = "";
str += "a";
str += "b";
str += "c";
str += "d";
上面的例子中,“a”、“b”、“c”、“d”都應該會首先在常量池中分配空間,是第一段程式碼效率更高
而str + "a" 會建立一個新的String物件,就慢了。你要知道String物件一旦建立就是不能被改變的,要達到字串拼接的效果,就得不停建立新物件,而建立新的物件時,有可能會觸發GC。
StringBuilder直到最後sb.toString()才會建立String物件,之前都沒有建立新物件,但是如果你append的總長度超過一定範圍——預設是16——就會建立一個新的陣列,來裝下更多的String。
也就是說 快得原因就是因為StringBuilder預先開闢了空間, append的時候只是向記憶體地址賦值; 而String總要不斷的現開闢空間. 也因此String佔的空間也會相對大。
StringBuilder和StringBuffer,字串是存放在char[]中的,char[]是存放在堆中的。
相比String每次+都重新建立一個String物件,重新開闢一段記憶體不同,StringBuilder和StringBuffer的append都是直接把String物件中的char[]的字元直接拷貝到StringBuilder和StringBuffer的char[]上,效率比String的+高得多。當然,當StringBuilder和StringBuffer的char[]長度不夠時,也會重新開闢一段記憶體。
另外,StringBuffer是執行緒安全的,StringBuilder不是執行緒安全的。
應用
下劃線轉駝峰
public static String underlineToCamel(String param){ if (param==null||"".equals(param.trim())){ return ""; } int len=param.length(); StringBuilder sb=new StringBuilder(len); for (int i = 0; i < len; i++) { char c = Character.toLowerCase(param.charAt(i)); if (c == UNDERLINE){ if (++i<len){ sb.append(Character.toUpperCase(param.charAt(i))); } }else{ sb.append(c); } } return sb.toString(); }
AbstractStringBuilder類的定義
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;
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
/**
* Returns the length (character count).
*
* @return the length of the sequence of characters currently
* represented by this object
*/
@Override
public int length() {
return count;
}
/**
* Returns the current capacity. The capacity is the amount of storage
* available for newly inserted characters, beyond which an allocation
* will occur.
*
* @return the current capacity
*/
public int capacity() {
return value.length;
}
@Override
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
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;
}
// Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
}
/**
* @since 1.8
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null)
return appendNull();
int len = asb.length();
ensureCapacityInternal(count + len);
asb.getChars(0, len, value, count);
count += len;
return this;
}
// Documentation in subclasses because of synchro difference
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);
return this.append(s, 0, s.length());
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
/**
* Appends a subsequence of the specified {@code CharSequence} to this
* sequence.
* <p>
* Characters of the argument {@code s}, starting at
* index {@code start}, are appended, in order, to the contents of
* this sequence up to the (exclusive) index {@code end}. The length
* of this sequence is increased by the value of {@code end - start}.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in this character sequence becomes equal to the
* character at index <i>k</i> in this sequence, if <i>k</i> is less than
* <i>n</i>; otherwise, it is equal to the character at index
* <i>k+start-n</i> in the argument {@code s}.
* <p>
* If {@code s} is {@code null}, then this method appends
* characters as if the s parameter was a sequence containing the four
* characters {@code "null"}.
*
* @param s the sequence to append.
* @param start the starting index of the subsequence to be appended.
* @param end the end index of the subsequence to be appended.
* @return a reference to this object.
* @throws IndexOutOfBoundsException if
* {@code start} is negative, or
* {@code start} is greater than {@code end} or
* {@code end} is greater than {@code s.length()}
*/
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
}
/**
* Appends the string representation of the {@code char} array
* argument to this sequence.
* <p>
* The characters of the array argument are appended, in order, to
* the contents of this sequence. The length of this sequence
* increases by the length of the argument.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(char[])},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param str the characters to be appended.
* @return a reference to this object.
*/
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(str, 0, value, count, len);
count += len;
return this;
}
/**
* Appends the string representation of a subarray of the
* {@code char} array argument to this sequence.
* <p>
* Characters of the {@code char} array {@code str}, starting at
* index {@code offset}, are appended, in order, to the contents
* of this sequence. The length of this sequence increases
* by the value of {@code len}.
* <p>
* The overall effect is exactly as if the arguments were converted
* to a string by the method {@link String#valueOf(char[],int,int)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param str the characters to be appended.
* @param offset the index of the first {@code char} to append.
* @param len the number of {@code char}s to append.
* @return a reference to this object.
* @throws IndexOutOfBoundsException
* if {@code offset < 0} or {@code len < 0}
* or {@code offset+len > str.length}
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
}
/**
* Appends the string representation of the {@code boolean}
* argument to the sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(boolean)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param b a {@code boolean}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
}
/**
* Appends the string representation of the {@code char}
* argument to this sequence.
* <p>
* The argument is appended to the contents of this sequence.
* The length of this sequence increases by {@code 1}.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(char)},
* and the character in that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param c a {@code char}.
* @return a reference to this object.
*/
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
/**
* Appends the string representation of the {@code int}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(int)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param i an {@code int}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
}
/**
* Appends the string representation of the {@code long}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(long)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param l a {@code long}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(long l) {
if (l == Long.MIN_VALUE) {
append("-9223372036854775808");
return this;
}
int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
: Long.stringSize(l);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Long.getChars(l, spaceNeeded, value);
count = spaceNeeded;
return this;
}
/**
* Appends the string representation of the {@code float}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(float)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param f a {@code float}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(float f) {
FloatingDecimal.appendTo(f,this);
return this;
}
/**
* Appends the string representation of the {@code double}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(double)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param d a {@code double}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(double d) {
FloatingDecimal.appendTo(d,this);
return this;
}
@Override
public abstract String toString();
/**
* Needed by {@code String} for the contentEquals method.
*/
final char[] getValue() {
return value;
}
}
Appendable介面定義
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
CharSequence介面定義
public interface CharSequence {
int length();
char charAt(int index);
CharSequence subSequence(int start, int end);
public String toString();
}
StringBuilder類定義
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
static final long serialVersionUID = 4383685877147921099L;
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
@Override
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
@Override
public StringBuilder append(char[] str) {
super.append(str);
return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
@Override
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
@Override
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
@Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
@Override
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
@Override
public StringBuilder append(float f) {
super.append(f);
return this;
}
@Override
public StringBuilder append(double d) {
super.append(d);
return this;
}
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
}