DEV Community

Siva Surya
Siva Surya

Posted on

System.in, Scanner, and File Descriptors – JAVA Case study

Hello, Everyone, I am currently learning Java. As a beginner, I worked with console IO. To read input from the terminal, I use the Scanner class.

I tried a mini CLI project, so I used the Scanner object in different classes. For resource management, the Scanner object — especially when reading from sources like System.in or files — utilizes underlying system resources (like file descriptors or input streams). Closing the Scanner explicitly releases these resources back to the operating system, preventing resource leaks.

So, I closed the Scanner in each class, but after running my program, I got this exception:

Exception in thread "main" java.util.NoSuchElementException
Enter fullscreen mode Exit fullscreen mode

This was the first time I saw this exception. After reading some related Stack Overflow discussions, I understood the real reason.


The Core Problem: Input Stream Closure

When a Scanner is closed, it also closes the underlying input stream it's connected to.
For example, if you create a Scanner from a FileInputStream, closing the Scanner will also close that FileInputStream. This ensures that all related resources are properly shut down.

But I wondered:

“If I create a new Scanner again, shouldn’t the JVM reopen the input stream?”

Surprisingly, no — and here’s why.


Example Code

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan1 = new Scanner(System.in);
        String ip1 = scan1.next();
        scan1.close();

        Scanner scan2 = new Scanner(System.in);
        String ip2 = scan2.next();  // throws Runtime exception
        scan2.close();
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

Exception in thread "main" java.util.NoSuchElementException
Enter fullscreen mode Exit fullscreen mode

What Actually Happens Under the Hood

  • System.in is a singleton InputStream provided by the JVM — not something that can be reopened automatically.
  • When you call scan1.close(), it calls System.in.close() internally.
  • This closes the standard input stream permanently for that JVM session.
  • Any subsequent Scanner (like scan2) tries to read from a closed input stream, so the JVM throws a NoSuchElementException or IllegalStateException.

So even though you created a new Scanner, it still points to the same closed System.in, not a fresh one.


What’s the Correct Practice?

If you’re reading from System.in, never close the Scanner until your entire program finishes reading all input.
You can safely reuse the same Scanner across methods or classes by passing it as a reference — but avoid closing it.

Example fix:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        String ip1 = scan.next();
        String ip2 = scan.next();

        scan.close();  // Close only once at the end
    }
}
Enter fullscreen mode Exit fullscreen mode

JVM and OS-Level Insight

  • System.in is typically linked to stdin (file descriptor 0) at the OS level.
  • Once closed, the OS releases that descriptor, and the JVM does not recreate it automatically.
  • Creating a new Scanner doesn’t reopen the descriptor — it just wraps the already-closed stream.

Key Takeaway

In Java, closing a Scanner created from System.in closes the entire standard input stream for the running JVM.
Always close it only once, at the end of the program — or better, let the JVM handle it automatically when the program exits.


That’s what I discovered in my small case study — a good reminder that not all resources can be reopened once closed, especially when they represent system-level standard streams.

Top comments (0)