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), //$NON-NLS-1$
52            new ObjectStreamField("shared", boolean.class), //$NON-NLS-1$
53            new ObjectStreamField("value", char[].class), }; //$NON-NLS-1$
54
55    /**
56     * Constructs a new StringBuffer using the default capacity which is 16.
57     */
58    public StringBuffer() {
59        super();
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"); //$NON-NLS-1$//$NON-NLS-2$
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        return append(Double.toString(d));
141    }
142
143    /**
144     * Adds the string representation of the specified float to the end of this
145     * StringBuffer.
146     *
147     * @param f
148     *            the float to append.
149     * @return this StringBuffer.
150     * @see String#valueOf(float)
151     */
152    public StringBuffer append(float f) {
153        return append(Float.toString(f));
154    }
155
156    /**
157     * Adds the string representation of the specified integer to the end of
158     * this StringBuffer.
159     *
160     * @param i
161     *            the integer to append.
162     * @return this StringBuffer.
163     * @see String#valueOf(int)
164     */
165    public StringBuffer append(int i) {
166        return append(Integer.toString(i));
167    }
168
169    /**
170     * Adds the string representation of the specified long to the end of this
171     * StringBuffer.
172     *
173     * @param l
174     *            the long to append.
175     * @return this StringBuffer.
176     * @see String#valueOf(long)
177     */
178    public StringBuffer append(long l) {
179        return append(Long.toString(l));
180    }
181
182    /**
183     * Adds the string representation of the specified object to the end of this
184     * StringBuffer.
185     * <p>
186     * If the specified object is {@code null} the string {@code "null"} is
187     * appended, otherwise the objects {@code toString} is used to get its
188     * string representation.
189     *
190     * @param obj
191     *            the object to append (may be null).
192     * @return this StringBuffer.
193     * @see String#valueOf(Object)
194     */
195    public synchronized StringBuffer append(Object obj) {
196        if (obj == null) {
197            appendNull();
198        } else {
199            append0(obj.toString());
200        }
201        return this;
202    }
203
204    /**
205     * Adds the specified string to the end of this buffer.
206     * <p>
207     * If the specified string is {@code null} the string {@code "null"} is
208     * appended, otherwise the contents of the specified string is appended.
209     *
210     * @param string
211     *            the string to append (may be null).
212     * @return this StringBuffer.
213     */
214    public synchronized StringBuffer append(String string) {
215        append0(string);
216        return this;
217    }
218
219    /**
220     * Adds the specified StringBuffer to the end of this buffer.
221     * <p>
222     * If the specified StringBuffer is {@code null} the string {@code "null"}
223     * is appended, otherwise the contents of the specified StringBuffer is
224     * appended.
225     *
226     * @param sb
227     *            the StringBuffer to append (may be null).
228     * @return this StringBuffer.
229     *
230     * @since 1.4
231     */
232    public synchronized StringBuffer append(StringBuffer sb) {
233        if (sb == null) {
234            appendNull();
235        } else {
236            synchronized (sb) {
237                append0(sb.getValue(), 0, sb.length());
238            }
239        }
240        return this;
241    }
242
243    /**
244     * Adds the character array to the end of this buffer.
245     *
246     * @param chars
247     *            the character array to append.
248     * @return this StringBuffer.
249     * @throws NullPointerException
250     *            if {@code chars} is {@code null}.
251     */
252    public synchronized StringBuffer append(char chars[]) {
253        append0(chars);
254        return this;
255    }
256
257    /**
258     * Adds the specified sequence of characters to the end of this buffer.
259     *
260     * @param chars
261     *            the character array to append.
262     * @param start
263     *            the starting offset.
264     * @param length
265     *            the number of characters.
266     * @return this StringBuffer.
267     * @throws ArrayIndexOutOfBoundsException
268     *             if {@code length < 0} , {@code start < 0} or {@code start +
269     *             length > chars.length}.
270     * @throws NullPointerException
271     *            if {@code chars} is {@code null}.
272     */
273    public synchronized StringBuffer append(char chars[], int start, int length) {
274        append0(chars, start, length);
275        return this;
276    }
277
278    /**
279     * Appends the specified CharSequence to this buffer.
280     * <p>
281     * If the specified CharSequence is {@code null} the string {@code "null"}
282     * is appended, otherwise the contents of the specified CharSequence is
283     * appended.
284     *
285     * @param s
286     *            the CharSequence to append.
287     * @return this StringBuffer.
288     * @since 1.5
289     */
290    public synchronized StringBuffer append(CharSequence s) {
291        if (s == null) {
292            appendNull();
293        } else {
294            append0(s.toString());
295        }
296        return this;
297    }
298
299    /**
300     * Appends the specified subsequence of the CharSequence to this buffer.
301     * <p>
302     * If the specified CharSequence is {@code null}, then the string {@code
303     * "null"} is used to extract a subsequence.
304     *
305     * @param s
306     *            the CharSequence to append.
307     * @param start
308     *            the inclusive start index.
309     * @param end
310     *            the exclusive end index.
311     * @return this StringBuffer.
312     * @throws IndexOutOfBoundsException
313     *             if {@code start} or {@code end} are negative, {@code start}
314     *             is greater than {@code end} or {@code end} is greater than
315     *             the length of {@code s}.
316     * @since 1.5
317     */
318    public synchronized StringBuffer append(CharSequence s, int start, int end) {
319        append0(s, start, end);
320        return this;
321    }
322
323    /**
324     * Appends the string representation of the specified Unicode code point to
325     * the end of this buffer.
326     * <p>
327     * The code point is converted to a {@code char[]} as defined by
328     * {@link Character#toChars(int)}.
329     *
330     * @param codePoint
331     *            the Unicode code point to encode and append.
332     * @return this StringBuffer.
333     * @see Character#toChars(int)
334     * @since 1.5
335     */
336    public StringBuffer appendCodePoint(int codePoint) {
337        return append(Character.toChars(codePoint));
338    }
339
340    @Override
341    public synchronized char charAt(int index) {
342        return super.charAt(index);
343    }
344
345    @Override
346    public synchronized int codePointAt(int index) {
347        return super.codePointAt(index);
348    }
349
350    @Override
351    public synchronized int codePointBefore(int index) {
352        return super.codePointBefore(index);
353    }
354
355    @Override
356    public synchronized int codePointCount(int beginIndex, int endIndex) {
357        return super.codePointCount(beginIndex, endIndex);
358    }
359
360    /**
361     * Deletes a range of characters.
362     *
363     * @param start
364     *            the offset of the first character.
365     * @param end
366     *            the offset one past the last character.
367     * @return this StringBuffer.
368     * @throws StringIndexOutOfBoundsException
369     *             if {@code start < 0}, {@code start > end} or {@code end >
370     *             length()}.
371     */
372    public synchronized StringBuffer delete(int start, int end) {
373        delete0(start, end);
374        return this;
375    }
376
377    /**
378     * Deletes the character at the specified offset.
379     *
380     * @param location
381     *            the offset of the character to delete.
382     * @return this StringBuffer.
383     * @throws StringIndexOutOfBoundsException
384     *             if {@code location < 0} or {@code location >= length()}
385     */
386    public synchronized StringBuffer deleteCharAt(int location) {
387        deleteCharAt0(location);
388        return this;
389    }
390
391    @Override
392    public synchronized void ensureCapacity(int min) {
393        super.ensureCapacity(min);
394    }
395
396    /**
397     * Copies the requested sequence of characters to the {@code char[]} passed
398     * starting at {@code idx}.
399     *
400     * @param start
401     *            the starting offset of characters to copy.
402     * @param end
403     *            the ending offset of characters to copy.
404     * @param buffer
405     *            the destination character array.
406     * @param idx
407     *            the starting offset in the character array.
408     * @throws IndexOutOfBoundsException
409     *             if {@code start < 0}, {@code end > length()}, {@code start >
410     *             end}, {@code index < 0}, {@code end - start > buffer.length -
411     *             index}
412     */
413    @Override
414    public synchronized void getChars(int start, int end, char[] buffer, int idx) {
415        super.getChars(start, end, buffer, idx);
416    }
417
418    @Override
419    public synchronized int indexOf(String subString, int start) {
420        return super.indexOf(subString, start);
421    }
422
423    /**
424     * Inserts the character into this buffer at the specified offset.
425     *
426     * @param index
427     *            the index at which to insert.
428     * @param ch
429     *            the character to insert.
430     * @return this buffer.
431     * @throws ArrayIndexOutOfBoundsException
432     *             if {@code index < 0} or {@code index > length()}.
433     */
434    public synchronized StringBuffer insert(int index, char ch) {
435        insert0(index, ch);
436        return this;
437    }
438
439    /**
440     * Inserts the string representation of the specified boolean into this
441     * buffer at the specified offset.
442     *
443     * @param index
444     *            the index at which to insert.
445     * @param b
446     *            the boolean to insert.
447     * @return this buffer.
448     * @throws StringIndexOutOfBoundsException
449     *             if {@code index < 0} or {@code index > length()}.
450     */
451    public StringBuffer insert(int index, boolean b) {
452        return insert(index, b ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$
453    }
454
455    /**
456     * Inserts the string representation of the specified integer into this
457     * buffer at the specified offset.
458     *
459     * @param index
460     *            the index at which to insert.
461     * @param i
462     *            the integer to insert.
463     * @return this buffer.
464     * @throws StringIndexOutOfBoundsException
465     *             if {@code index < 0} or {@code index > length()}.
466     */
467    public StringBuffer insert(int index, int i) {
468        return insert(index, Integer.toString(i));
469    }
470
471    /**
472     * Inserts the string representation of the specified long into this buffer
473     * at the specified offset.
474     *
475     * @param index
476     *            the index at which to insert.
477     * @param l
478     *            the long to insert.
479     * @return this buffer.
480     * @throws StringIndexOutOfBoundsException
481     *             if {@code index < 0} or {@code index > length()}.
482     */
483    public StringBuffer insert(int index, long l) {
484        return insert(index, Long.toString(l));
485    }
486
487    /**
488     * Inserts the string representation of the specified into this buffer
489     * double at the specified offset.
490     *
491     * @param index
492     *            the index at which to insert.
493     * @param d
494     *            the double to insert.
495     * @return this buffer.
496     * @throws StringIndexOutOfBoundsException
497     *             if {@code index < 0} or {@code index > length()}.
498     */
499    public StringBuffer insert(int index, double d) {
500        return insert(index, Double.toString(d));
501    }
502
503    /**
504     * Inserts the string representation of the specified float into this buffer
505     * at the specified offset.
506     *
507     * @param index
508     *            the index at which to insert.
509     * @param f
510     *            the float to insert.
511     * @return this buffer.
512     * @throws StringIndexOutOfBoundsException
513     *             if {@code index < 0} or {@code index > length()}.
514     */
515    public StringBuffer insert(int index, float f) {
516        return insert(index, Float.toString(f));
517    }
518
519    /**
520     * Inserts the string representation of the specified object into this
521     * buffer at the specified offset.
522     * <p>
523     * If the specified object is {@code null}, the string {@code "null"} is
524     * inserted, otherwise the objects {@code toString} method is used to get
525     * its string representation.
526     *
527     * @param index
528     *            the index at which to insert.
529     * @param obj
530     *            the object to insert (may be null).
531     * @return this buffer.
532     * @throws StringIndexOutOfBoundsException
533     *             if {@code index < 0} or {@code index > length()}.
534     */
535    public StringBuffer insert(int index, Object obj) {
536        return insert(index, obj == null ? "null" : obj.toString()); //$NON-NLS-1$
537    }
538
539    /**
540     * Inserts the string into this buffer at the specified offset.
541     * <p>
542     * If the specified string is {@code null}, the string {@code "null"} is
543     * inserted, otherwise the contents of the string is inserted.
544     *
545     * @param index
546     *            the index at which to insert.
547     * @param string
548     *            the string to insert (may be null).
549     * @return this buffer.
550     * @throws StringIndexOutOfBoundsException
551     *             if {@code index < 0} or {@code index > length()}.
552     */
553    public synchronized StringBuffer insert(int index, String string) {
554        insert0(index, string);
555        return this;
556    }
557
558    /**
559     * Inserts the character array into this buffer at the specified offset.
560     *
561     * @param index
562     *            the index at which to insert.
563     * @param chars
564     *            the character array to insert.
565     * @return this buffer.
566     * @throws StringIndexOutOfBoundsException
567     *             if {@code index < 0} or {@code index > length()}.
568     * @throws NullPointerException
569     *            if {@code chars} is {@code null}.
570     */
571    public synchronized StringBuffer insert(int index, char[] chars) {
572        insert0(index, chars);
573        return this;
574    }
575
576    /**
577     * Inserts the specified subsequence of characters into this buffer at the
578     * specified index.
579     *
580     * @param index
581     *            the index at which to insert.
582     * @param chars
583     *            the character array to insert.
584     * @param start
585     *            the starting offset.
586     * @param length
587     *            the number of characters.
588     * @return this buffer.
589     * @throws NullPointerException
590     *             if {@code chars} is {@code null}.
591     * @throws StringIndexOutOfBoundsException
592     *             if {@code length < 0}, {@code start < 0}, {@code start +
593     *             length > chars.length}, {@code index < 0} or {@code index >
594     *             length()}
595     */
596    public synchronized StringBuffer insert(int index, char chars[], int start,
597            int length) {
598        insert0(index, chars, start, length);
599        return this;
600    }
601
602    /**
603     * Inserts the specified CharSequence into this buffer at the specified
604     * index.
605     * <p>
606     * If the specified CharSequence is {@code null}, the string {@code "null"}
607     * is inserted, otherwise the contents of the CharSequence.
608     *
609     * @param index
610     *            The index at which to insert.
611     * @param s
612     *            The char sequence to insert.
613     * @return this buffer.
614     * @throws IndexOutOfBoundsException
615     *             if {@code index < 0} or {@code index > length()}.
616     * @since 1.5
617     */
618    public synchronized StringBuffer insert(int index, CharSequence s) {
619        insert0(index, s == null ? "null" : s.toString()); //$NON-NLS-1$
620        return this;
621    }
622
623    /**
624     * Inserts the specified subsequence into this buffer at the specified
625     * index.
626     * <p>
627     * If the specified CharSequence is {@code null}, the string {@code "null"}
628     * is inserted, otherwise the contents of the CharSequence.
629     *
630     * @param index
631     *            The index at which to insert.
632     * @param s
633     *            The char sequence to insert.
634     * @param start
635     *            The inclusive start index in the char sequence.
636     * @param end
637     *            The exclusive end index in the char sequence.
638     * @return this buffer.
639     * @throws IndexOutOfBoundsException
640     *             if {@code index} is negative or greater than the current
641     *             length, {@code start} or {@code end} are negative, {@code
642     *             start} is greater than {@code end} or {@code end} is greater
643     *             than the length of {@code s}.
644     * @since 1.5
645     */
646    public synchronized StringBuffer insert(int index, CharSequence s,
647            int start, int end) {
648        insert0(index, s, start, end);
649        return this;
650    }
651
652    @Override
653    public synchronized int lastIndexOf(String subString, int start) {
654        return super.lastIndexOf(subString, start);
655    }
656
657    @Override
658    public synchronized int offsetByCodePoints(int index, int codePointOffset) {
659        return super.offsetByCodePoints(index, codePointOffset);
660    }
661
662    /**
663     * Replaces the characters in the specified range with the contents of the
664     * specified string.
665     *
666     * @param start
667     *            the inclusive begin index.
668     * @param end
669     *            the exclusive end index.
670     * @param string
671     *            the string that will replace the contents in the range.
672     * @return this buffer.
673     * @throws StringIndexOutOfBoundsException
674     *             if {@code start} or {@code end} are negative, {@code start}
675     *             is greater than {@code end} or {@code end} is greater than
676     *             the length of {@code s}.
677     */
678    public synchronized StringBuffer replace(int start, int end, String string) {
679        replace0(start, end, string);
680        return this;
681    }
682
683    /**
684     * Reverses the order of characters in this buffer.
685     *
686     * @return this buffer.
687     */
688    public synchronized StringBuffer reverse() {
689        reverse0();
690        return this;
691    }
692
693    @Override
694    public synchronized void setCharAt(int index, char ch) {
695        super.setCharAt(index, ch);
696    }
697
698    @Override
699    public synchronized void setLength(int length) {
700        super.setLength(length);
701    }
702
703    @Override
704    public synchronized CharSequence subSequence(int start, int end) {
705        return super.substring(start, end);
706    }
707
708    @Override
709    public synchronized String substring(int start) {
710        return super.substring(start);
711    }
712
713    @Override
714    public synchronized String substring(int start, int end) {
715        return super.substring(start, end);
716    }
717
718    @Override
719    public synchronized String toString() {
720        return super.toString();
721    }
722
723    @Override
724    public synchronized void trimToSize() {
725        super.trimToSize();
726    }
727
728    private synchronized void writeObject(ObjectOutputStream out)
729            throws IOException {
730        ObjectOutputStream.PutField fields = out.putFields();
731        fields.put("count", length()); //$NON-NLS-1$
732        fields.put("shared", false); //$NON-NLS-1$
733        fields.put("value", getValue()); //$NON-NLS-1$
734        out.writeFields();
735    }
736
737    private void readObject(ObjectInputStream in) throws IOException,
738            ClassNotFoundException {
739        ObjectInputStream.GetField fields = in.readFields();
740        int count = fields.get("count", 0); //$NON-NLS-1$
741        char[] value = (char[]) fields.get("value", null); //$NON-NLS-1$
742        set(value, count);
743    }
744}
745