1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.lang;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.ObjectStreamField;
24import java.io.Serializable;
25
26/**
27 * A modifiable {@link CharSequence sequence of characters} for use in creating
28 * strings, where all accesses are synchronized. This class has mostly been replaced
29 * by {@link StringBuilder} because this synchronization is rarely useful. This
30 * class is mainly used to interact with legacy APIs that expose it.
31 *
32 * <p>For particularly complex string-building needs, consider {@link java.util.Formatter}.
33 *
34 * <p>The majority of the modification methods on this class return {@code
35 * this} so that method calls can be chained together. For example:
36 * {@code new StringBuffer("a").append("b").append("c").toString()}.
37 *
38 * @see CharSequence
39 * @see Appendable
40 * @see StringBuilder
41 * @see String
42 * @see String#format
43 * @since 1.0
44 */
45public final class StringBuffer extends AbstractStringBuilder implements
46        Appendable, Serializable, CharSequence {
47
48    private static final long serialVersionUID = 3388685877147921107L;
49
50    private static final ObjectStreamField[] serialPersistentFields = {
51        new ObjectStreamField("count", int.class),
52        new ObjectStreamField("shared", boolean.class),
53        new ObjectStreamField("value", char[].class),
54    };
55
56    /**
57     * Constructs a new StringBuffer using the default capacity which is 16.
58     */
59    public StringBuffer() {
60    }
61
62    /**
63     * Constructs a new StringBuffer using the specified capacity.
64     *
65     * @param capacity
66     *            the initial capacity.
67     */
68    public StringBuffer(int capacity) {
69        super(capacity);
70    }
71
72    /**
73     * Constructs a new StringBuffer containing the characters in the specified
74     * string. The capacity of the new buffer will be the length of the
75     * {@code String} plus the default capacity.
76     *
77     * @param string
78     *            the string content with which to initialize the new instance.
79     * @throws NullPointerException
80     *            if {@code string} is {@code null}.
81     */
82    public StringBuffer(String string) {
83        super(string);
84    }
85
86    /**
87     * Constructs a StringBuffer and initializes it with the content from the
88     * specified {@code CharSequence}. The capacity of the new buffer will be
89     * the length of the {@code CharSequence} plus the default capacity.
90     *
91     * @param cs
92     *            the content to initialize the instance.
93     * @throws NullPointerException
94     *            if {@code cs} is {@code null}.
95     * @since 1.5
96     */
97    public StringBuffer(CharSequence cs) {
98        super(cs.toString());
99    }
100
101    /**
102     * Adds the string representation of the specified boolean to the end of
103     * this StringBuffer.
104     * <p>
105     * If the argument is {@code true} the string {@code "true"} is appended,
106     * otherwise the string {@code "false"} is appended.
107     *
108     * @param b
109     *            the boolean to append.
110     * @return this StringBuffer.
111     * @see String#valueOf(boolean)
112     */
113    public StringBuffer append(boolean b) {
114        return append(b ? "true" : "false");
115    }
116
117    /**
118     * Adds the specified character to the end of this buffer.
119     *
120     * @param ch
121     *            the character to append.
122     * @return this StringBuffer.
123     * @see String#valueOf(char)
124     */
125    public synchronized StringBuffer append(char ch) {
126        append0(ch);
127        return this;
128    }
129
130    /**
131     * Adds the string representation of the specified double to the end of this
132     * StringBuffer.
133     *
134     * @param d
135     *            the double to append.
136     * @return this StringBuffer.
137     * @see String#valueOf(double)
138     */
139    public StringBuffer append(double d) {
140        RealToString.getInstance().appendDouble(this, d);
141        return this;
142    }
143
144    /**
145     * Adds the string representation of the specified float to the end of this
146     * StringBuffer.
147     *
148     * @param f
149     *            the float to append.
150     * @return this StringBuffer.
151     * @see String#valueOf(float)
152     */
153    public StringBuffer append(float f) {
154        RealToString.getInstance().appendFloat(this, f);
155        return this;
156    }
157
158    /**
159     * Adds the string representation of the specified integer to the end of
160     * this StringBuffer.
161     *
162     * @param i
163     *            the integer to append.
164     * @return this StringBuffer.
165     * @see String#valueOf(int)
166     */
167    public StringBuffer append(int i) {
168        IntegralToString.appendInt(this, i);
169        return this;
170    }
171
172    /**
173     * Adds the string representation of the specified long to the end of this
174     * StringBuffer.
175     *
176     * @param l
177     *            the long to append.
178     * @return this StringBuffer.
179     * @see String#valueOf(long)
180     */
181    public StringBuffer append(long l) {
182        IntegralToString.appendLong(this, l);
183        return this;
184    }
185
186    /**
187     * Adds the string representation of the specified object to the end of this
188     * StringBuffer.
189     * <p>
190     * If the specified object is {@code null} the string {@code "null"} is
191     * appended, otherwise the objects {@code toString} is used to get its
192     * string representation.
193     *
194     * @param obj
195     *            the object to append (may be null).
196     * @return this StringBuffer.
197     * @see String#valueOf(Object)
198     */
199    public synchronized StringBuffer append(Object obj) {
200        if (obj == null) {
201            appendNull();
202        } else {
203            append0(obj.toString());
204        }
205        return this;
206    }
207
208    /**
209     * Adds the specified string to the end of this buffer.
210     * <p>
211     * If the specified string is {@code null} the string {@code "null"} is
212     * appended, otherwise the contents of the specified string is appended.
213     *
214     * @param string
215     *            the string to append (may be null).
216     * @return this StringBuffer.
217     */
218    public synchronized StringBuffer append(String string) {
219        append0(string);
220        return this;
221    }
222
223    /**
224     * Adds the specified StringBuffer to the end of this buffer.
225     * <p>
226     * If the specified StringBuffer is {@code null} the string {@code "null"}
227     * is appended, otherwise the contents of the specified StringBuffer is
228     * appended.
229     *
230     * @param sb
231     *            the StringBuffer to append (may be null).
232     * @return this StringBuffer.
233     *
234     * @since 1.4
235     */
236    public synchronized StringBuffer append(StringBuffer sb) {
237        if (sb == null) {
238            appendNull();
239        } else {
240            synchronized (sb) {
241                append0(sb.getValue(), 0, sb.length());
242            }
243        }
244        return this;
245    }
246
247    /**
248     * Adds the character array to the end of this buffer.
249     *
250     * @param chars
251     *            the character array to append.
252     * @return this StringBuffer.
253     * @throws NullPointerException
254     *            if {@code chars} is {@code null}.
255     */
256    public synchronized StringBuffer append(char[] chars) {
257        append0(chars);
258        return this;
259    }
260
261    /**
262     * Adds the specified sequence of characters to the end of this buffer.
263     *
264     * @param chars
265     *            the character array to append.
266     * @param start
267     *            the starting offset.
268     * @param length
269     *            the number of characters.
270     * @return this StringBuffer.
271     * @throws ArrayIndexOutOfBoundsException
272     *             if {@code length < 0} , {@code start < 0} or {@code start +
273     *             length > chars.length}.
274     * @throws NullPointerException
275     *            if {@code chars} is {@code null}.
276     */
277    public synchronized StringBuffer append(char[] chars, int start, int length) {
278        append0(chars, start, length);
279        return this;
280    }
281
282    /**
283     * Appends the specified CharSequence to this buffer.
284     * <p>
285     * If the specified CharSequence is {@code null} the string {@code "null"}
286     * is appended, otherwise the contents of the specified CharSequence is
287     * appended.
288     *
289     * @param s
290     *            the CharSequence to append.
291     * @return this StringBuffer.
292     * @since 1.5
293     */
294    public synchronized StringBuffer append(CharSequence s) {
295        if (s == null) {
296            appendNull();
297        } else {
298            append0(s, 0, s.length());
299        }
300        return this;
301    }
302
303    /**
304     * Appends the specified subsequence of the CharSequence to this buffer.
305     * <p>
306     * If the specified CharSequence is {@code null}, then the string {@code
307     * "null"} is used to extract a subsequence.
308     *
309     * @param s
310     *            the CharSequence to append.
311     * @param start
312     *            the inclusive start index.
313     * @param end
314     *            the exclusive end index.
315     * @return this StringBuffer.
316     * @throws IndexOutOfBoundsException
317     *             if {@code start} or {@code end} are negative, {@code start}
318     *             is greater than {@code end} or {@code end} is greater than
319     *             the length of {@code s}.
320     * @since 1.5
321     */
322    public synchronized StringBuffer append(CharSequence s, int start, int end) {
323        append0(s, start, end);
324        return this;
325    }
326
327    /**
328     * Appends the string representation of the specified Unicode code point to
329     * the end of this buffer.
330     * <p>
331     * The code point is converted to a {@code char[]} as defined by
332     * {@link Character#toChars(int)}.
333     *
334     * @param codePoint
335     *            the Unicode code point to encode and append.
336     * @return this StringBuffer.
337     * @see Character#toChars(int)
338     * @since 1.5
339     */
340    public StringBuffer appendCodePoint(int codePoint) {
341        return append(Character.toChars(codePoint));
342    }
343
344    @Override
345    public synchronized char charAt(int index) {
346        return super.charAt(index);
347    }
348
349    @Override
350    public synchronized int codePointAt(int index) {
351        return super.codePointAt(index);
352    }
353
354    @Override
355    public synchronized int codePointBefore(int index) {
356        return super.codePointBefore(index);
357    }
358
359    @Override
360    public synchronized int codePointCount(int beginIndex, int endIndex) {
361        return super.codePointCount(beginIndex, endIndex);
362    }
363
364    /**
365     * Deletes a range of characters.
366     *
367     * @param start
368     *            the offset of the first character.
369     * @param end
370     *            the offset one past the last character.
371     * @return this StringBuffer.
372     * @throws StringIndexOutOfBoundsException
373     *             if {@code start < 0}, {@code start > end} or {@code end >
374     *             length()}.
375     */
376    public synchronized StringBuffer delete(int start, int end) {
377        delete0(start, end);
378        return this;
379    }
380
381    /**
382     * Deletes the character at the specified offset.
383     *
384     * @param location
385     *            the offset of the character to delete.
386     * @return this StringBuffer.
387     * @throws StringIndexOutOfBoundsException
388     *             if {@code location < 0} or {@code location >= length()}
389     */
390    public synchronized StringBuffer deleteCharAt(int location) {
391        deleteCharAt0(location);
392        return this;
393    }
394
395    @Override
396    public synchronized void ensureCapacity(int min) {
397        super.ensureCapacity(min);
398    }
399
400    /**
401     * Copies the requested sequence of characters to the {@code char[]} passed
402     * starting at {@code idx}.
403     *
404     * @param start
405     *            the starting offset of characters to copy.
406     * @param end
407     *            the ending offset of characters to copy.
408     * @param buffer
409     *            the destination character array.
410     * @param idx
411     *            the starting offset in the character array.
412     * @throws IndexOutOfBoundsException
413     *             if {@code start < 0}, {@code end > length()}, {@code start >
414     *             end}, {@code index < 0}, {@code end - start > buffer.length -
415     *             index}
416     */
417    @Override
418    public synchronized void getChars(int start, int end, char[] buffer, int idx) {
419        super.getChars(start, end, buffer, idx);
420    }
421
422    @Override
423    public synchronized int indexOf(String subString, int start) {
424        return super.indexOf(subString, start);
425    }
426
427    /**
428     * Inserts the character into this buffer at the specified offset.
429     *
430     * @param index
431     *            the index at which to insert.
432     * @param ch
433     *            the character to insert.
434     * @return this buffer.
435     * @throws ArrayIndexOutOfBoundsException
436     *             if {@code index < 0} or {@code index > length()}.
437     */
438    public synchronized StringBuffer insert(int index, char ch) {
439        insert0(index, ch);
440        return this;
441    }
442
443    /**
444     * Inserts the string representation of the specified boolean into this
445     * buffer at the specified offset.
446     *
447     * @param index
448     *            the index at which to insert.
449     * @param b
450     *            the boolean to insert.
451     * @return this buffer.
452     * @throws StringIndexOutOfBoundsException
453     *             if {@code index < 0} or {@code index > length()}.
454     */
455    public StringBuffer insert(int index, boolean b) {
456        return insert(index, b ? "true" : "false");
457    }
458
459    /**
460     * Inserts the string representation of the specified integer into this
461     * buffer at the specified offset.
462     *
463     * @param index
464     *            the index at which to insert.
465     * @param i
466     *            the integer to insert.
467     * @return this buffer.
468     * @throws StringIndexOutOfBoundsException
469     *             if {@code index < 0} or {@code index > length()}.
470     */
471    public StringBuffer insert(int index, int i) {
472        return insert(index, Integer.toString(i));
473    }
474
475    /**
476     * Inserts the string representation of the specified long into this buffer
477     * at the specified offset.
478     *
479     * @param index
480     *            the index at which to insert.
481     * @param l
482     *            the long to insert.
483     * @return this buffer.
484     * @throws StringIndexOutOfBoundsException
485     *             if {@code index < 0} or {@code index > length()}.
486     */
487    public StringBuffer insert(int index, long l) {
488        return insert(index, Long.toString(l));
489    }
490
491    /**
492     * Inserts the string representation of the specified into this buffer
493     * double at the specified offset.
494     *
495     * @param index
496     *            the index at which to insert.
497     * @param d
498     *            the double to insert.
499     * @return this buffer.
500     * @throws StringIndexOutOfBoundsException
501     *             if {@code index < 0} or {@code index > length()}.
502     */
503    public StringBuffer insert(int index, double d) {
504        return insert(index, Double.toString(d));
505    }
506
507    /**
508     * Inserts the string representation of the specified float into this buffer
509     * at the specified offset.
510     *
511     * @param index
512     *            the index at which to insert.
513     * @param f
514     *            the float to insert.
515     * @return this buffer.
516     * @throws StringIndexOutOfBoundsException
517     *             if {@code index < 0} or {@code index > length()}.
518     */
519    public StringBuffer insert(int index, float f) {
520        return insert(index, Float.toString(f));
521    }
522
523    /**
524     * Inserts the string representation of the specified object into this
525     * buffer at the specified offset.
526     * <p>
527     * If the specified object is {@code null}, the string {@code "null"} is
528     * inserted, otherwise the objects {@code toString} method is used to get
529     * its string representation.
530     *
531     * @param index
532     *            the index at which to insert.
533     * @param obj
534     *            the object to insert (may be null).
535     * @return this buffer.
536     * @throws StringIndexOutOfBoundsException
537     *             if {@code index < 0} or {@code index > length()}.
538     */
539    public StringBuffer insert(int index, Object obj) {
540        return insert(index, obj == null ? "null" : obj.toString());
541    }
542
543    /**
544     * Inserts the string into this buffer at the specified offset.
545     * <p>
546     * If the specified string is {@code null}, the string {@code "null"} is
547     * inserted, otherwise the contents of the string is inserted.
548     *
549     * @param index
550     *            the index at which to insert.
551     * @param string
552     *            the string to insert (may be null).
553     * @return this buffer.
554     * @throws StringIndexOutOfBoundsException
555     *             if {@code index < 0} or {@code index > length()}.
556     */
557    public synchronized StringBuffer insert(int index, String string) {
558        insert0(index, string);
559        return this;
560    }
561
562    /**
563     * Inserts the character array into this buffer at the specified offset.
564     *
565     * @param index
566     *            the index at which to insert.
567     * @param chars
568     *            the character array to insert.
569     * @return this buffer.
570     * @throws StringIndexOutOfBoundsException
571     *             if {@code index < 0} or {@code index > length()}.
572     * @throws NullPointerException
573     *            if {@code chars} is {@code null}.
574     */
575    public synchronized StringBuffer insert(int index, char[] chars) {
576        insert0(index, chars);
577        return this;
578    }
579
580    /**
581     * Inserts the specified subsequence of characters into this buffer at the
582     * specified index.
583     *
584     * @param index
585     *            the index at which to insert.
586     * @param chars
587     *            the character array to insert.
588     * @param start
589     *            the starting offset.
590     * @param length
591     *            the number of characters.
592     * @return this buffer.
593     * @throws NullPointerException
594     *             if {@code chars} is {@code null}.
595     * @throws StringIndexOutOfBoundsException
596     *             if {@code length < 0}, {@code start < 0}, {@code start +
597     *             length > chars.length}, {@code index < 0} or {@code index >
598     *             length()}
599     */
600    public synchronized StringBuffer insert(int index, char[] chars, int start, int length) {
601        insert0(index, chars, start, length);
602        return this;
603    }
604
605    /**
606     * Inserts the specified CharSequence into this buffer at the specified
607     * index.
608     * <p>
609     * If the specified CharSequence is {@code null}, the string {@code "null"}
610     * is inserted, otherwise the contents of the CharSequence.
611     *
612     * @param index
613     *            The index at which to insert.
614     * @param s
615     *            The char sequence to insert.
616     * @return this buffer.
617     * @throws IndexOutOfBoundsException
618     *             if {@code index < 0} or {@code index > length()}.
619     * @since 1.5
620     */
621    public synchronized StringBuffer insert(int index, CharSequence s) {
622        insert0(index, s == null ? "null" : s.toString());
623        return this;
624    }
625
626    /**
627     * Inserts the specified subsequence into this buffer at the specified
628     * index.
629     * <p>
630     * If the specified CharSequence is {@code null}, the string {@code "null"}
631     * is inserted, otherwise the contents of the CharSequence.
632     *
633     * @param index
634     *            The index at which to insert.
635     * @param s
636     *            The char sequence to insert.
637     * @param start
638     *            The inclusive start index in the char sequence.
639     * @param end
640     *            The exclusive end index in the char sequence.
641     * @return this buffer.
642     * @throws IndexOutOfBoundsException
643     *             if {@code index} is negative or greater than the current
644     *             length, {@code start} or {@code end} are negative, {@code
645     *             start} is greater than {@code end} or {@code end} is greater
646     *             than the length of {@code s}.
647     * @since 1.5
648     */
649    public synchronized StringBuffer insert(int index, CharSequence s,
650            int start, int end) {
651        insert0(index, s, start, end);
652        return this;
653    }
654
655    @Override
656    public synchronized int lastIndexOf(String subString, int start) {
657        return super.lastIndexOf(subString, start);
658    }
659
660    @Override
661    public synchronized int offsetByCodePoints(int index, int codePointOffset) {
662        return super.offsetByCodePoints(index, codePointOffset);
663    }
664
665    /**
666     * Replaces the characters in the specified range with the contents of the
667     * specified string.
668     *
669     * @param start
670     *            the inclusive begin index.
671     * @param end
672     *            the exclusive end index.
673     * @param string
674     *            the string that will replace the contents in the range.
675     * @return this buffer.
676     * @throws StringIndexOutOfBoundsException
677     *             if {@code start} or {@code end} are negative, {@code start}
678     *             is greater than {@code end} or {@code end} is greater than
679     *             the length of {@code s}.
680     */
681    public synchronized StringBuffer replace(int start, int end, String string) {
682        replace0(start, end, string);
683        return this;
684    }
685
686    /**
687     * Reverses the order of characters in this buffer.
688     *
689     * @return this buffer.
690     */
691    public synchronized StringBuffer reverse() {
692        reverse0();
693        return this;
694    }
695
696    @Override
697    public synchronized void setCharAt(int index, char ch) {
698        super.setCharAt(index, ch);
699    }
700
701    @Override
702    public synchronized void setLength(int length) {
703        super.setLength(length);
704    }
705
706    @Override
707    public synchronized CharSequence subSequence(int start, int end) {
708        return super.substring(start, end);
709    }
710
711    @Override
712    public synchronized String substring(int start) {
713        return super.substring(start);
714    }
715
716    @Override
717    public synchronized String substring(int start, int end) {
718        return super.substring(start, end);
719    }
720
721    @Override
722    public synchronized String toString() {
723        return super.toString();
724    }
725
726    @Override
727    public synchronized void trimToSize() {
728        super.trimToSize();
729    }
730
731    private synchronized void writeObject(ObjectOutputStream out)
732            throws IOException {
733        ObjectOutputStream.PutField fields = out.putFields();
734        fields.put("count", length());
735        fields.put("shared", false);
736        fields.put("value", getValue());
737        out.writeFields();
738    }
739
740    private void readObject(ObjectInputStream in) throws IOException,
741            ClassNotFoundException {
742        ObjectInputStream.GetField fields = in.readFields();
743        int count = fields.get("count", 0);
744        char[] value = (char[]) fields.get("value", null);
745        set(value, count);
746    }
747}
748