<div dir="ltr"><p dir="ltr">Hi Markus,<br>
I think the idea makes sense, but it comes with more difficulties than in the case of Reader.of. An Appendable is a higher abstraction modeling only the character writing aspects, without concerns with resource control (such as flush or close).</p><p dir="ltr">One detail of note is that Writer itself implements Appendable, but I don't think the new method should return a Writer as-is; I think it should return another writer whose close will not close the underlying writer as we are only modelling the appendable behavior without exporting the resource control methods. Not sure about flush.</p><p>One use case you have mentioned is StringWriter. StringWriter is distinct from StringReader: its write and append methods do not throw IOE while the base Writer does. So Writer.of cannot adequately replace StringWriter without use-site ugliness, until we have generic types that represent the bottom type.</p><p>Regards,</p><p>Chen Liang</p></div>
<br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Dec 20, 2024, 11:12 PM Markus KARG <<a href="mailto:markus@headcrashing.eu" target="_blank">markus@headcrashing.eu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Dear Sirs,<br>
<br>
JDK 24 comes with Reader.of(CharSequence), now let's provide the <br>
symmetrical counterpart Writer.of(Appendable) in JDK 25! :-)<br>
<br>
For performance reasons, hereby I like to propose the new public factory <br>
method Writer.of(Appendable). This will provide the same benefits for <br>
writing, that Reader.of(CharSequence) provides for reading since JDK 24 <br>
(see JDK-8341566). Before sharing a pull request, I'd kindly like to <br>
request for comments.<br>
<br>
Since Java 1.1 we have the StringWriter class. Since Java 1.5 we have <br>
the Appendable interface. StringBuilder, StringBuffer and CharBuffer are <br>
first-class implementations of it in the JDK, and there might exist <br>
third-party implementations of non-String text sinks. Until today, <br>
however, we do not have a Writer for Appendables, but need to go costly <br>
detours.<br>
<br>
Text sinks in Java are expected to implement the Writer interface. <br>
Libraries and frameworks expect application code to provide Writers to <br>
consume text produced by the library or framework, for example. <br>
Application code often wants to modify the received text, e. g. embed <br>
received SVG text into in a larger HTML text document, or simply forward <br>
the text as-is to I/O, so StringBuilder or CharBuffer is what the <br>
application code actually uses, but not Strings! In such cases, taking <br>
the StringWriter.toString() detour is common but inefficient: It implies <br>
duplicating the COMPLETE text for the sole sake of creating a temporary <br>
String, while the subsequent processing will copy the data anyways or <br>
just uses a small piece of it. This eats up time and memory uselessly, <br>
and increases GC pressure. Also, StringWriter is synchronized (not <br>
explicitly, but de-facto, as it uses StringBuffer), which implies <br>
another needless slowdown. In many cases, the synchronization has no use <br>
at all, as in real-world applications least Writers are actually <br>
accessed concurrently. As a result, today the major benefit of <br>
StringBuilder over StringBuffer (being non-synchronized) vanishes as <br>
soon as a StringWriter is used to provide its content. This means, <br>
"stringBuilder.append(stringWriter.toString())" imposes slower <br>
performance than essentially needed, in two ways: toString(), synchronized.<br>
<br>
In an attempt to improve performance of this rather typical use case, I <br>
like to contribute a pull request providing the new public factory <br>
method java.io.Writer.of(Appendable). This is symmetrical to the <br>
solution we implemented in JDK-8341566 for the reversed case: <br>
java.io.Reader.of(CharSequence).<br>
<br>
My idea is to mostly copy the existing code of StringWriter, but wrap a <br>
caller-provided Appendable instead of an internally created <br>
StringBuilder; this strips synchronization; then add optimized use for <br>
the StringBuffer, StringBuilder and CharBuffer implementations (in the <br>
sense of write(char[],start,end) to prevent a char-by-char loop in these <br>
cases).<br>
<br>
Alternatives:<br>
<br>
- Applications could use Apache Commons IO's StringBuilderWriter, which <br>
is limited to StringBuilder, so is not usable for the CharBuffer or <br>
custom Appendable case. As it is an open-source third-party dependency, <br>
some authors might not be allowed to use it, or may not want to carry <br>
this additional burden just for the sake of this single performance <br>
improvement. In addition, this library is not actively modernized; its <br>
Java baseline still is Java 8. There is no commercial support.<br>
<br>
- Applications could write their own Writer implementation. Given the <br>
assumption that this is a rather common use case, this imposes <br>
unjustified additional work for the authors of thousands of <br>
applications. It is hard to justify why there is a StringWriter but not <br>
a Writer for other Appendables.<br>
<br>
- Instead of writing a new Writer factory method, we could slightly <br>
modify StringWriter, so it uses StringBuilder (instead of StringBuffer). <br>
This (still) results in unnecessary duplication of the full text at <br>
toString() and (now also) at getBuffer(), and it will break existing <br>
applications due the missing synchronization.<br>
<br>
- Instead of writing a new Writer factory method, we could write a new <br>
AppendableWriter class. This piles up the amount of public classes, <br>
which was the main reason in JDK-8341566 to go with the <br>
"Reader.of(CharSequence)" factory method instead of the <br>
"CharSequenceReader" class. Also it would be confusing to have <br>
Reader.of(...) but not Writer.of(...) in the API.<br>
<br>
- We could go with a specific Appendable class (like StringBuilder) <br>
instead of supporting all Appendable implementations. This would reduce <br>
the number of applicable use cases daramatically (in particular as <br>
CharBuffer is not supported any more) without providing any considerable <br>
benefit (other than making the OpenJDK-internal source code a bit <br>
shorter). In particular it makes it impossible to opt-in for the below <br>
option:<br>
<br>
Option:<br>
<br>
- Once we have Writer.of(Appendable), we could replace the full <br>
implementation of StringWriter by synchronized calls to the new Writer. <br>
This would reduce duplicate code.<br>
<br>
Kindly requesting comments.<br>
<br>
-Markus Karg<br>
<br>
</blockquote></div>