15 questions found
How would you correctly handle character encoding when reading a text file whose encoding isn't known in advance (or might not be UTF-8), and what pitfalls exist with relying on the JVM's platform default charset?
Advanced
Relying on the platform default charset (via a Reader/Writer constructor overload that doesn't explicitly specify one, like the older new FileReader(path) constructor) is a well-known cross-platform portability pitfall, since the default charset varies by operating system and locale configuration (historically Windows commonly defaulted to a different charset than Linux/macOS), meaning identical code could silently produce different, incorrect results when run on different machines -- as of Java 18, the JVM's default charset changed to always be UTF-8 regardless of platform (a significant, deliberate compatibility-improving change, JEP 400), but explicitly specifying the charset in every I/O call remains strongly recommended best practice regardless, both as defensive coding style and for genuine clarity about the actual expected encoding of the specific file being read.
// Risky (pre-Java 18): relies on platform default, which varies!
Reader reader1 = new FileReader("data.txt"); // encoding depends on the running JVM's platform default
// Always correct and explicit, regardless of JVM version or platform
Reader reader2 = new InputStreamReader(new FileInputStream("data.txt"), StandardCharsets.UTF_8);
// NIO.2 equivalent, also explicit
List<String> lines = Files.readAllLines(Path.of("data.txt"), StandardCharsets.UTF_8);
Real-world example
A cross-platform application that worked correctly on the development team's Linux machines produced garbled text output when deployed to a Windows server prior to Java 18, traced to code relying on the platform default charset (which differed between the two operating systems), fixed by explicitly specifying UTF-8 in every file I/O call throughout the codebase.
Common follow-ups: What changed specifically in JEP 400 (Java 18) regarding the default charset, and does it fully eliminate the need to specify charsets explicitly?;How would you detect or guess a file's actual encoding if it genuinely isn't known or documented in advance?
Java Fundamentals: Syntax
Data Types & Operators;Diagnostics & Performance
What is the purpose of the PrintStream and PrintWriter classes (like System.out), and how do they differ from lower-level OutputStream/Writer in their exception-handling behavior?
Intermediate
PrintStream (System.out is one) and PrintWriter provide convenient formatted-output methods (print(), println(), printf()) for a wide variety of types, and notably NEVER throw checked IOException from their write methods -- instead, any underlying I/O error sets an internal error flag (checkable via checkError()) that calling code can optionally inspect, rather than requiring every single print statement throughout a codebase to be wrapped in a try-catch or declare a checked exception, a deliberate ergonomic trade-off making these classes convenient for everyday console/simple output use, at the cost of making I/O failures easier to silently miss if checkError() is never actually consulted.
PrintWriter writer = new PrintWriter(new FileWriter("output.txt"));
writer.println("Hello"); // no checked exception to handle, unlike a raw Writer's write() method
writer.printf("Value: %d%n", 42);
if (writer.checkError()) { // must be explicitly checked -- easy to forget!
System.err.println("An I/O error occurred during writing, but was silently absorbed");
}
writer.close();
Real-world example
A logging utility built on PrintWriter for its ergonomic printf()-style formatting occasionally silently loses log entries during a disk-full scenario, since the code never called checkError() to detect the internally-flagged write failures, an important design consideration when choosing PrintWriter's convenience over a lower-level Writer that would have forced explicit exception handling.
Common follow-ups: Why did the JDK designers choose to suppress checked exceptions specifically for PrintStream/PrintWriter but not other I/O classes?;What's the relationship between System.out (a PrintStream) and redirecting console output to a file via System.setOut()?
Exceptions;Logging in Java (java.util.logging
SLF4J
Log4j)
How do you read all bytes or all lines of a small-to-medium text file in a single, concise call using modern NIO.2 utility methods?
Beginner
For files small enough to comfortably fit entirely in memory, Files.readString(path) (Java 11+) reads an entire file's content as a single String in one call, and Files.readAllLines(path) reads it as a List<String> (one element per line) -- both dramatically more concise than the older manual approach of opening a BufferedReader and looping with readLine(), appropriate specifically for smaller files where loading everything into memory at once isn't a concern (for very large files, a streaming approach like Files.lines() returning a lazily-evaluated Stream<String> avoids loading the entire file into memory at once).
// Read entire file as one String (Java 11+)
String content = Files.readString(Path.of("config.json"));
// Read entire file as a List of lines
List<String> lines = Files.readAllLines(Path.of("data.csv"));
// For large files: lazily-streamed line-by-line processing instead
try (Stream<String> lineStream = Files.lines(Path.of("huge.log"))) {
long errorCount = lineStream.filter(line -> line.contains("ERROR")).count();
}
Real-world example
A configuration-loading utility reads an entire small JSON config file into a String using the concise Files.readString() one-liner, replacing what would have previously required several lines of manual BufferedReader setup, reading, and closing.
Common follow-ups: At what file size does loading the entire file into memory with readAllLines()/readString() become a genuine concern versus using a streaming approach?;What charset does Files.readString() assume by default, and how would you specify a different one?
Java Fundamentals: Syntax
Data Types & Operators;File Uploads & Streaming Large Files
How would you recursively copy an entire directory tree (including all subdirectories and files) using the Files.walkFileTree() method and a FileVisitor implementation?
Intermediate
Files.walkFileTree(startPath, visitor) traverses an entire directory tree, invoking callback methods on a supplied FileVisitor implementation at specific points (preVisitDirectory before entering a directory, visitFile for each regular file, postVisitDirectory after finishing a directory, and visitFileFailed if an error occurs accessing a particular file) -- implementing a recursive copy involves creating the corresponding destination directory structure in preVisitDirectory and copying each individual file's content in visitFile, giving fine-grained control over the traversal (like selectively skipping certain subdirectories) that a simpler flat directory listing wouldn't provide.
Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Path targetDir = destDir.resolve(sourceDir.relativize(dir));
Files.createDirectories(targetDir);
return FileVisitResult.CONTINUE;
}
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.copy(file, destDir.resolve(sourceDir.relativize(file)), StandardCopyOption.REPLACE_EXISTING);
return FileVisitResult.CONTINUE;
}
});
Real-world example
A backup utility recursively copies an entire project directory (preserving its full subdirectory structure) using Files.walkFileTree() with a custom FileVisitor, additionally skipping any directory named 'node_modules' or '.git' by returning FileVisitResult.SKIP_SUBTREE from preVisitDirectory for those specific directory names.
Common follow-ups: How does Files.walk() (returning a Stream<Path>) compare to Files.walkFileTree() in terms of flexibility and use case fit?;What's the purpose of the FileVisitResult return value, and what other options besides CONTINUE exist?
File Uploads & Streaming Large Files;Diagnostics & Performance
How would you implement file locking (using FileLock) to coordinate exclusive access to a shared file across multiple processes, and what are the platform-specific reliability caveats?
Advanced
FileChannel.lock() (blocking) or tryLock() (non-blocking, returns null if unavailable rather than waiting) acquires an advisory OS-level file lock on all or part of a file, coordinating access between multiple processes (not just threads within the same JVM) attempting to read/write the same file concurrently -- an important caveat is that file locks in Java are advisory on most platforms (meaning they only prevent conflicts between processes that explicitly check for and respect the lock, not an OS-enforced hard restriction preventing any access whatsoever), and locking behavior/reliability can vary meaningfully across operating systems and especially over network file systems (NFS), making file-based locking a reasonably reliable coordination mechanism for local, single-machine scenarios but a poor choice for distributed coordination across multiple machines, where a dedicated distributed lock service is more appropriate.
try (FileChannel channel = FileChannel.open(Path.of("shared.lock"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {
FileLock lock = channel.tryLock();
if (lock == null) {
System.out.println("Another process already holds the lock");
return;
}
try {
// perform exclusive work protected by the lock
} finally {
lock.release();
}
}
Real-world example
A scheduled batch job that should only ever run as a single instance across a cluster of application servers sharing a network file system uses FileLock as a simple coordination mechanism to prevent duplicate concurrent runs, while acknowledging the team's awareness that this approach carries known reliability caveats specifically over network file systems compared to local disk.
Common follow-ups: Why is advisory locking considered less robust than mandatory locking, and what does 'advisory' specifically mean in this context?;What would be a more robust alternative for coordinating exclusive execution across multiple machines in a distributed system?
Concurrency & Threads;Background Tasks & Hosted Services