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