Java Scanner Unclosed Stream — Too Many Open Files Error
Unclosed Scanner exhausts file descriptors after ~1020 files, causing 'Too many open files' error.
- Java I/O is how programs read input and write output using streams.
- The main output tools are System.out.print, println, and printf.
- Input is handled by Scanner (for user input) or BufferedReader (for speed).
- Performance insight: BufferedReader is ~3x faster than Scanner for bulk reads because it buffers large chunks.
- Production insight: Unclosed Scanner objects leak file handles — always close or use try-with-resources.
- Biggest mistake: Mixing nextInt() with nextLine() without flushing the leftover newline.
Think of your Java program as a chef in a kitchen. Input is the customer's order — information coming IN to the chef so they know what to cook. Output is the finished meal placed on the table — information going OUT from the chef back to the customer. Just like a restaurant needs a system for taking orders and serving food, Java needs a system for reading data and printing results. That system is what Input and Output (I/O) is all about.
Every useful program in the world does at least one of two things: it takes information in, or it sends information out. Your phone's calculator takes in numbers you tap and outputs an answer. A login screen takes in your password and outputs either a welcome screen or an error. Without input and output, a program just runs silently in a box and does nothing anyone can see. That's why I/O is the very first real-world skill you need as a Java developer — it's how your program talks to the outside world.
Printing to the Console — Java's Built-In Megaphone
Before your program can accept input, it needs to be able to speak. Printing to the console is Java's way of shouting a message to whoever is running the program. Think of it like a scoreboard at a sports game — it's how the program announces what's happening.
Java gives you three closely related tools for this, and beginners often use them interchangeably without understanding the differences. System.out.println() prints your message and then moves the cursor to a new line — like pressing Enter after typing. System.out.print() prints your message but stays on the same line, so the next thing printed appears right next to it. System.out.printf() is the most powerful — it lets you format your output precisely, like lining up numbers in a table.
System is a built-in Java class that represents your computer's environment. out is the output stream attached to your console. And println, print, and printf are the methods you call on it. You don't need to import anything — Java includes System automatically in every program.
Reading User Input with Scanner — Java's Ears
Printing is only half the story. A program that can't accept input is like a vending machine with no buttons — it just sits there. Java's Scanner class is your go-to tool for reading what a user types into the console.
Scanner lives in the java.util package, so you must import it at the top of your file before you can use it. You create one Scanner object and keep it for the whole program — creating a new Scanner every time you want to read input is wasteful and causes bugs.
Once you have a Scanner, you call different methods depending on what type of data you're expecting. nextLine() reads a whole line of text including spaces. reads only one word (stops at a space). next()nextInt() reads an integer. nextDouble() reads a decimal number. The Scanner pauses the program and waits for the user to type something and press Enter — that pause is called blocking, and it's intentional.
Always close your Scanner when you're done using it. It's connected to a resource (the keyboard input stream), and leaving it open is a memory leak waiting to happen.
Handling the nextInt/nextLine Bug and Input Validation
This bug trips up almost every beginner, so it deserves its own section. When you mix nextInt() or nextDouble() with nextLine(), the Scanner's internal buffer causes a silent but nasty problem. Let's look at exactly what happens and how to fix it cleanly.
Imagine the user types 25 and presses Enter. What's actually in the buffer is 25 . When you call nextInt(), it reads 25 but leaves the sitting in the buffer. The very next nextLine() sees that and says 'I found a newline — my job is done!' and returns an empty string before the user has a chance to type anything.
The reliable fix is to call keyboardInput.nextLine() immediately after any nextInt() or nextDouble() call — think of it as 'draining the leftover newline from the pipe.' Alternatively, you can read everything as strings using nextLine() and then parse the number yourself with Integer.parseInt() or Double.parseDouble(). The second approach also lets you show a friendly error message when the user types something unexpected instead of crashing.
BufferedReader — The Faster, More Powerful Alternative
Scanner is perfect for learning and small programs, but professional Java developers often use BufferedReader for console input instead. The key difference is speed and control — BufferedReader reads large chunks of data at once (buffering them in memory), which is significantly faster when processing big files or high-throughput input.
BufferedReader requires a bit more setup. You wrap System.in in an InputStreamReader (which converts raw bytes to characters) and then wrap that in a BufferedReader (which adds efficient line-by-line reading). It sounds complex, but it's always the same three lines of setup code and you'll memorise them quickly.
The main trade-off: BufferedReader only reads strings — you always get back a String from readLine(), and you have to parse it yourself to get numbers. It also throws a checked IOException which means Java forces you to either handle it with try-catch or declare it with throws IOException. For beginners, Scanner is the right starting point. As you grow into professional Java, reach for BufferedReader.
In the code below, notice how both approaches produce the same result — the choice is about performance and context, not correctness.
close() manually (and risking forgetting it), wrap your BufferedReader in a try-with-resources block: try (BufferedReader reader = new BufferedReader(...)) { ... }. Java will automatically close it when the block ends, even if an exception is thrown. This is the professional pattern.Reading from Files with Scanner and Writing with PrintWriter
Console input is just the start. In real applications, input often comes from files — configuration files, data logs, CSV exports. Java's Scanner can read from files just as easily as from the keyboard. You just pass a File object instead of System.in. For writing output to files, PrintWriter is the equivalent of System.out.
Scanner automatically handles different data types when reading from files. hasNextLine() is your friend here — it returns true if there's another line in the file, letting you loop safely without hitting NoSuchElementException. For writing, PrintWriter provides println, print, and printf just like System.out. But you must flush or close it to ensure data actually hits the disk.
The common mistake is assuming Scanner will skip empty lines or that PrintWriter automatically flushes. PrintWriter's autoFlush is false by default — if you forget to close, you lose output.
Let's see a complete example: reading customer data from a CSV file and writing a formatted report to another file.
flush() means data loss.Unclosed Scanner in Batch Job Exhausts File Handles
- Always close I/O resources — never rely on garbage collection.
- Use try-with-resources for any resource that implements AutoCloseable.
- Monitor file descriptor count on production servers.
System.in.close() unless you intend to. Use hasNextLine/hasNextInt before reading.lsof -p <pid> | wc -l to check open file handles. Find unclosed Scanner/BufferedReader instances and wrap them in try-with-resources.scanner.nextLine() after nextInt to flush the newline buffer. Alternatively, switch to reading all input as strings.BufferedReader.readLine() returns null unexpectedly(line = reader.readLine()) != null. Also verify that the InputStream hasn't been closed externally.scanner.nextLine(); immediately after every nextInt/nextDouble/nextFloat call before reading a line.Key takeaways
System.out.println() adds a newline after printing; System.out.print() doesn'timport java.util.Scanner and must be wrapped around System.inCommon mistakes to avoid
4 patternsCalling nextLine() immediately after nextInt() without buffer flush
Forgetting to import Scanner
import java.util.Scanner; as the very first line after your package declaration. This import is mandatory; Scanner is not automatically available like System is.Using nextLine() to read a number and skipping parseInt/parseDouble conversion
Not closing Scanner when reading a file
try (Scanner sc = new Scanner(new File("data.txt"))) { ... } — Java closes it automatically.Interview Questions on This Topic
What is the difference between System.out.print(), System.out.println(), and System.out.printf() in Java? When would you choose each one?
print outputs text without a newline. println appends a newline after output. printf uses format specifiers for structured formatting. Use printf for reports or tables where alignment matters. Use print for prompts. Use println for general output.Frequently Asked Questions
That's Java Basics. Mark it forged?
4 min read · try the examples if you haven't