I/O, Serialization & Networking
Readers, Writers & Character Encodings
Reader/Writer handle text: bytes decoded to characters through a Charset. Specify UTF-8 explicitly at every boundary — encoding bugs are silent, cumulative, and international.- Text = bytes + encoding; without the encoding, bytes are meaningless
- Since Java 18, UTF-8 is the default charset everywhere — but be explicit at boundaries anyway
InputStreamReader/OutputStreamWriterbridge byte ↔ char streamsBufferedReader.lines()streams a file lazily;Scannerparses tokensPrintWriterfor human-oriented output (println,printf)
try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
reader.lines()
.filter(line -> !line.isBlank())
.forEach(this::process);
}
try (var writer = new PrintWriter(
Files.newBufferedWriter(path, StandardCharsets.UTF_8))) {
writer.printf("%-20s %8.2f%n", name, amount);
}
String whole = Files.readString(path); // small files
Files.writeString(path, content);The mojibake mechanism: writer encodes é as UTF-8 (0xC3 0xA9), reader decodes as Windows-1252 and displays é. Nothing throws — the data is just wrong, and a second round trip compounds it. Every historical "default charset" call site was a latent bug on the machine with a different locale; Java 18's UTF-8 default (JEP 400) fixed the default, not the principle: name the charset at every I/O boundary you don't control.
var sc = new Scanner(System.in); // tokenizing: words, ints, patterns
int age = sc.nextInt();
var console = System.console(); // echo-free password entry
char[] pw = console.readPassword("Password: ");