はじめに
CharSequence
は文字の並びを表すインターフェースで、その実装には String
に加え StringBuffer
, StringBuilder
, CharBuffer
などがあります。
CharSequence
から Reader を得るには、以下のように一度文字列に変換する必要がありました。
var r = new StringReader(cs.toString());
なお、Commons IO が使える環境であれば、以下で済みます。
var r = new org.apache.commons.io.input.CharSequenceReader(cs);
java.io.Reader.of()
JDK 24 では、Reader
に以下のスタティックメソッドが追加され、CharSequence
から Reader を取得できるようになりました。
public static Reader of(final CharSequence cs) { // ... }
このメソッドでは、引数の CharSequence
をラップした Reader
の匿名クラスを返すため、toString()
による無駄なインスタンスの生成を抑制できます。
文字の読み込みは、以下のように CharSequence
の実装により切り替える実装になっています。
public static Reader of(final CharSequence cs) { return new Reader() { // ... @Override public int read(char[] cbuf, int off, int len) throws IOException { // ... switch (cs) { case String s -> s.getChars(next, next + n, cbuf, off); case StringBuilder sb -> sb.getChars(next, next + n, cbuf, off); case StringBuffer sb -> sb.getChars(next, next + n, cbuf, off); case CharBuffer cb -> cb.get(next, cbuf, off, n); default -> { for (int i = 0; i < n; i++) cbuf[off + i] = cs.charAt(next + i); } } next += n; return n; } }
CharSequence
を実装した未知のクラスに対しては、char 単位でのループ処理にフォールバックされるので、パフォーマンスを重視する場面では注意する必要があります。
また、Reader.of()
で取得した Reader
は同期処理が省かれているため、マルチスレッド環境で利用する場合は自身で同期処理を行うか、旧来通り StringReader
を利用します(こちらは同期処理が含まれています)。
JDK11 で追加された nullReader()
と合わせて、Reader
には2つのスタティックファクトリメソッドが存在することになります。
public abstract class Reader implements Readable, Closeable { public static Reader nullReader() { ... } public static Reader of(final CharSequence cs) { ... } }
nullReader()
は、読み込みに対して常にストリームの終端に達しているような結果を返し、close()
後は IOException
をスローします。
ちなみに nullReader()
に応当する nullWriter()
も JDK11 で追加されており、こちらは書き込まれた全ての文字を単に破棄します。いずれもテストなどの状況で利用することを想定したものになります。
public abstract class Writer implements Appendable, Closeable, Flushable { public static Writer nullWriter() { } }
まとめ
あえて書くほどでもない小さな話ではありますが、
JDK 24 で java.io.Reader.of(CharSequence)
が追加されました。
このスタティックファクトリメソッドを使うことで CharSequence
からの Reader
生成パフォーマンスの改善が期待できます。
生成した Reader
に複数スレッドからアクセスする場合は、自身で同期処理を行うか、旧来通り StringReader
を利用してください。