自分が書いた Java プログラムが以下のエラーを出力した。
Caused by: java.nio.charset.MalformedInputException: Input length = 1
at java.base/java.nio.charset.CoderResult.throwException(CoderResult.java:274)
at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:306)
at java.base/sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:281)
at java.base/sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.base/java.io.OutputStreamWriter.write(OutputStreamWriter.java:211)
at java.base/java.io.BufferedWriter.flushBuffer(BufferedWriter.java:120)
at java.base/java.io.BufferedWriter.flush(BufferedWriter.java:256)
(以下、アプリケーションコードのスタックトレース部分を省略)
文字エンコーディングに関する問題であることはすぐわかるが、次のアプリケーションコードの該当箇所を見ても理由が思い当たらない。
File file = ...;
try (BufferedWriter writer = java.nio.file.Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
String s = ...;
writer.write(s);
writer.flush(); // ここでエラーが出るので直前の write の引数が怪しいが...
}
こういうときは文字列の s をダンプして s の中身を調べるのが常套手段。
System.err.println("[" + s + "]");
とすると、以下のように表示された。? は何だろう、文字化けか?
そもそも、System.err#println
だとエラーが出ないのか...
[?]
ここで サロゲートペア にすぐ気づかなかったのは迂闊であった。
以下のコードで s の各文字を調べると、 High.
が表示された。最初のエラーの原因はこれだ。
for (char c : s.toCharArray()) {
if (Character.isHighSurrogate(c)) {
System.err.println("High.");
}
if (Character.isLowSurrogate(c)) {
System.err.println("Low.");
}
}
2020年現在、サロゲートペアをきちんと考慮した Java プログラミングは、常識のお作法であろうか。