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 
18 package java.io;
19 
20 import java.util.Arrays;
21 
22 /**
23  * A specialized {@link Writer} that writes characters to a {@code StringBuffer}
24  * in a sequential manner, appending them in the process. The result can later
25  * be queried using the {@link #StringWriter(int)} or {@link #toString()}
26  * methods.
27  *
28  * @see StringReader
29  */
30 public class StringWriter extends Writer {
31 
32     private StringBuffer buf;
33 
34     /**
35      * Constructs a new {@code StringWriter} which has a {@link StringBuffer}
36      * allocated with the default size of 16 characters. The {@code
37      * StringBuffer} is also the {@code lock} used to synchronize access to this
38      * writer.
39      */
StringWriter()40     public StringWriter() {
41         buf = new StringBuffer(16);
42         lock = buf;
43     }
44 
45     /**
46      * Constructs a new {@code StringWriter} which has a {@link StringBuffer}
47      * allocated with a size of {@code initialSize} characters. The {@code
48      * StringBuffer} is also the {@code lock} used to synchronize access to this
49      * writer.
50      *
51      * @param initialSize
52      *            the initial size of the target string buffer.
53      */
StringWriter(int initialSize)54     public StringWriter(int initialSize) {
55         if (initialSize < 0) {
56             throw new IllegalArgumentException("initialSize < 0: " + initialSize);
57         }
58         buf = new StringBuffer(initialSize);
59         lock = buf;
60     }
61 
62     /**
63      * Calling this method has no effect. In contrast to most {@code Writer} subclasses,
64      * the other methods in {@code StringWriter} do not throw an {@code IOException} if
65      * {@code close()} has been called.
66      *
67      * @throws IOException
68      *             if an error occurs while closing this writer.
69      */
70     @Override
close()71     public void close() throws IOException {
72         /* empty */
73     }
74 
75     /**
76      * Calling this method has no effect.
77      */
78     @Override
flush()79     public void flush() {
80         /* empty */
81     }
82 
83     /**
84      * Gets a reference to this writer's internal {@link StringBuffer}. Any
85      * changes made to the returned buffer are reflected in this writer.
86      *
87      * @return a reference to this writer's internal {@code StringBuffer}.
88      */
getBuffer()89     public StringBuffer getBuffer() {
90         return buf;
91     }
92 
93     /**
94      * Gets a copy of the contents of this writer as a string.
95      *
96      * @return this writer's contents as a string.
97      */
98     @Override
toString()99     public String toString() {
100         return buf.toString();
101     }
102 
103     /**
104      * Writes {@code count} characters starting at {@code offset} in {@code buf}
105      * to this writer's {@code StringBuffer}.
106      *
107      * @param chars
108      *            the non-null character array to write.
109      * @param offset
110      *            the index of the first character in {@code chars} to write.
111      * @param count
112      *            the maximum number of characters to write.
113      * @throws IndexOutOfBoundsException
114      *             if {@code offset < 0} or {@code count < 0}, or if {@code
115      *             offset + count} is greater than the size of {@code buf}.
116      */
117     @Override
write(char[] chars, int offset, int count)118     public void write(char[] chars, int offset, int count) {
119         Arrays.checkOffsetAndCount(chars.length, offset, count);
120         if (count == 0) {
121             return;
122         }
123         buf.append(chars, offset, count);
124     }
125 
126     /**
127      * Writes one character to this writer's {@code StringBuffer}. Only the two
128      * least significant bytes of the integer {@code oneChar} are written.
129      *
130      * @param oneChar
131      *            the character to write to this writer's {@code StringBuffer}.
132      */
133     @Override
write(int oneChar)134     public void write(int oneChar) {
135         buf.append((char) oneChar);
136     }
137 
138     /**
139      * Writes the characters from the specified string to this writer's {@code
140      * StringBuffer}.
141      *
142      * @param str
143      *            the non-null string containing the characters to write.
144      */
145     @Override
write(String str)146     public void write(String str) {
147         buf.append(str);
148     }
149 
150     /**
151      * Writes {@code count} characters from {@code str} starting at {@code
152      * offset} to this writer's {@code StringBuffer}.
153      *
154      * @param str
155      *            the non-null string containing the characters to write.
156      * @param offset
157      *            the index of the first character in {@code str} to write.
158      * @param count
159      *            the number of characters from {@code str} to write.
160      * @throws StringIndexOutOfBoundsException
161      *             if {@code offset < 0} or {@code count < 0}, or if {@code
162      *             offset + count} is greater than the length of {@code str}.
163      */
164     @Override
write(String str, int offset, int count)165     public void write(String str, int offset, int count) {
166         String sub = str.substring(offset, offset + count);
167         buf.append(sub);
168     }
169 
170     /**
171      * Appends the character {@code c} to this writer's {@code StringBuffer}.
172      * This method works the same way as {@link #write(int)}.
173      *
174      * @param c
175      *            the character to append to the target stream.
176      * @return this writer.
177      */
178     @Override
append(char c)179     public StringWriter append(char c) {
180         write(c);
181         return this;
182     }
183 
184     /**
185      * Appends the character sequence {@code csq} to this writer's {@code
186      * StringBuffer}. This method works the same way as {@code
187      * StringWriter.write(csq.toString())}. If {@code csq} is {@code null}, then
188      * the string "null" is written to the target stream.
189      *
190      * @param csq
191      *            the character sequence appended to the target.
192      * @return this writer.
193      */
194     @Override
append(CharSequence csq)195     public StringWriter append(CharSequence csq) {
196         if (csq == null) {
197             csq = "null";
198         }
199         write(csq.toString());
200         return this;
201     }
202 
203     /**
204      * Appends a subsequence of the character sequence {@code csq} to this
205      * writer's {@code StringBuffer}. This method works the same way as {@code
206      * StringWriter.writer(csq.subsequence(start, end).toString())}. If {@code
207      * csq} is {@code null}, then the specified subsequence of the string "null"
208      * will be written to the target.
209      *
210      * @param csq
211      *            the character sequence appended to the target.
212      * @param start
213      *            the index of the first char in the character sequence appended
214      *            to the target.
215      * @param end
216      *            the index of the character following the last character of the
217      *            subsequence appended to the target.
218      * @return this writer.
219      * @throws IndexOutOfBoundsException
220      *             if {@code start > end}, {@code start < 0}, {@code end < 0} or
221      *             either {@code start} or {@code end} are greater or equal than
222      *             the length of {@code csq}.
223      */
224     @Override
append(CharSequence csq, int start, int end)225     public StringWriter append(CharSequence csq, int start, int end) {
226         if (csq == null) {
227             csq = "null";
228         }
229         String output = csq.subSequence(start, end).toString();
230         write(output, 0, output.length());
231         return this;
232     }
233 }
234