Skip to content

Commit 0bf767b

Browse files
committedDec 18, 2024·
Writer.of(Appendable)
1 parent 5b703c7 commit 0bf767b

File tree

2 files changed

+155
-11
lines changed

2 files changed

+155
-11
lines changed
 

‎src/java.base/share/classes/java/io/StringWriter.java

+42-11
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,18 @@
3636
* can be called after the stream has been closed without generating an
3737
* {@code IOException}.
3838
*
39+
* @apiNote
40+
* {@link Writer#of(Appendable)} provides a method to write into any
41+
* {@link Appendable} that may be more efficient than {@code StringWriter}.
42+
*
3943
* @author Mark Reinhold
4044
* @since 1.1
4145
*/
4246

4347
public class StringWriter extends Writer {
4448

4549
private final StringBuffer buf;
50+
private final Writer w;
4651

4752
/**
4853
* Create a new string writer using the default initial string-buffer
@@ -51,6 +56,7 @@ public class StringWriter extends Writer {
5156
public StringWriter() {
5257
buf = new StringBuffer();
5358
lock = buf;
59+
w = Writer.of(buf);
5460
}
5561

5662
/**
@@ -70,13 +76,18 @@ public StringWriter(int initialSize) {
7076
}
7177
buf = new StringBuffer(initialSize);
7278
lock = buf;
79+
w = Writer.of(buf);
7380
}
7481

7582
/**
7683
* Write a single character.
7784
*/
7885
public void write(int c) {
79-
buf.append((char) c);
86+
try {
87+
w.write(c);
88+
} catch (IOException e) {
89+
throw new UncheckedIOException(e);
90+
}
8091
}
8192

8293
/**
@@ -92,18 +103,22 @@ public void write(int c) {
92103
* of the given array
93104
*/
94105
public void write(char[] cbuf, int off, int len) {
95-
Objects.checkFromIndexSize(off, len, cbuf.length);
96-
if (len == 0) {
97-
return;
106+
try {
107+
w.write(cbuf, off, len);
108+
} catch (IOException e) {
109+
throw new UncheckedIOException(e);
98110
}
99-
buf.append(cbuf, off, len);
100111
}
101112

102113
/**
103114
* Write a string.
104115
*/
105116
public void write(String str) {
106-
buf.append(str);
117+
try {
118+
w.write(str);
119+
} catch (IOException e) {
120+
throw new UncheckedIOException(e);
121+
}
107122
}
108123

109124
/**
@@ -119,7 +134,11 @@ public void write(String str) {
119134
* of the given string
120135
*/
121136
public void write(String str, int off, int len) {
122-
buf.append(str, off, off + len);
137+
try {
138+
w.write(str, off, len);
139+
} catch (IOException e) {
140+
throw new UncheckedIOException(e);
141+
}
123142
}
124143

125144
/**
@@ -149,7 +168,11 @@ public void write(String str, int off, int len) {
149168
* @since 1.5
150169
*/
151170
public StringWriter append(CharSequence csq) {
152-
write(String.valueOf(csq));
171+
try {
172+
w.append(csq);
173+
} catch (IOException e) {
174+
throw new UncheckedIOException(e);
175+
}
153176
return this;
154177
}
155178

@@ -188,8 +211,12 @@ public StringWriter append(CharSequence csq) {
188211
* @since 1.5
189212
*/
190213
public StringWriter append(CharSequence csq, int start, int end) {
191-
if (csq == null) csq = "null";
192-
return append(csq.subSequence(start, end));
214+
try {
215+
w.append(csq, start, end);
216+
} catch (IOException e) {
217+
throw new UncheckedIOException(e);
218+
}
219+
return this;
193220
}
194221

195222
/**
@@ -210,7 +237,11 @@ public StringWriter append(CharSequence csq, int start, int end) {
210237
* @since 1.5
211238
*/
212239
public StringWriter append(char c) {
213-
write(c);
240+
try {
241+
w.append(c);
242+
} catch (IOException e) {
243+
throw new UncheckedIOException(e);
244+
}
214245
return this;
215246
}
216247

‎src/java.base/share/classes/java/io/Writer.java

+113
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
package java.io;
2727

28+
import java.nio.CharBuffer;
2829
import java.util.Objects;
2930

3031
/**
@@ -144,6 +145,118 @@ public void close() throws IOException {
144145
};
145146
}
146147

148+
/**
149+
* Returns a {@code Writer} that writes characters into an
150+
* {@code Appendable}. The writer is initially open and writing appends
151+
* after the last character in the builder.
152+
*
153+
* <p> The resulting writer is not safe for use by multiple
154+
* concurrent threads. If the writer is to be used by more than one
155+
* thread it should be controlled by appropriate synchronization.
156+
*
157+
* <p> If the appendable changes while the writer is open, e.g. the length
158+
* changes, the behavior is undefined.
159+
*
160+
* @param a {@code Appendable} consuming the character stream.
161+
* @return a {@code Writer} which writes characters into {@code a}
162+
* @throws NullPointerException if {@code a} is {@code null}
163+
*
164+
* @since 25
165+
*/
166+
public static Writer of(final Appendable a) {
167+
Objects.requireNonNull(a);
168+
169+
return new Writer() {
170+
private boolean isClosed;
171+
172+
/** Check to make sure that the stream has not been closed */
173+
private void ensureOpen() throws IOException {
174+
if (isClosed)
175+
throw new IOException("Stream closed");
176+
}
177+
178+
@Override
179+
public void write(int c) throws IOException {
180+
ensureOpen();
181+
switch (a) {
182+
case Writer w -> w.write(c);
183+
default -> a.append((char) c);
184+
}
185+
}
186+
187+
@Override
188+
public void write(char[] cbuf, int off, int len) throws IOException {
189+
ensureOpen();
190+
Objects.checkFromIndexSize(off, len, cbuf.length);
191+
if (len == 0) {
192+
return;
193+
}
194+
switch (a) {
195+
case StringBuilder sb -> sb.append(cbuf, off, len);
196+
case StringBuffer sb -> sb.append(cbuf, off, len);
197+
case CharBuffer cb -> cb.put(cbuf, off, len);
198+
case Writer w -> w.write(cbuf, off, len);
199+
default -> {
200+
for (int i = 0; i < len; i++)
201+
a.append(cbuf[off + i]);
202+
}
203+
}
204+
}
205+
206+
@Override
207+
public void write(String str) throws IOException {
208+
ensureOpen();
209+
switch (a) {
210+
case StringBuilder sb -> sb.append(str);
211+
case StringBuffer sb -> sb.append(str);
212+
case CharBuffer cb -> cb.put(str);
213+
case Writer w -> w.write(str);
214+
default -> a.append(str);
215+
}
216+
}
217+
218+
@Override
219+
public void write(String str, int off, int len) throws IOException {
220+
ensureOpen();
221+
switch (a) {
222+
case Writer w -> w.write(str, off, len);
223+
default -> a.append(str, off, off + len);
224+
}
225+
}
226+
227+
@Override
228+
public Writer append(CharSequence csq) throws IOException {
229+
ensureOpen();
230+
a.append(csq);
231+
return this;
232+
}
233+
234+
@Override
235+
public Writer append(CharSequence csq, int start, int end) throws IOException {
236+
ensureOpen();
237+
a.append(csq, start, end);
238+
return this;
239+
}
240+
241+
@Override
242+
public Writer append(char c) throws IOException {
243+
ensureOpen();
244+
a.append(c);
245+
return this;
246+
}
247+
248+
@Override
249+
public void flush() throws IOException {
250+
ensureOpen();
251+
}
252+
253+
@Override
254+
public void close() throws IOException {
255+
isClosed = true;
256+
}
257+
};
258+
}
259+
147260
/**
148261
* The object used to synchronize operations on this stream. For
149262
* efficiency, a character-stream object may use an object other than

0 commit comments

Comments
 (0)
Please sign in to comment.