How to Close a Scanner in Java (And Why It Matters)

If you've written Java programs that read input — from the keyboard, a file, or a network stream — you've almost certainly used the Scanner class. Knowing how to properly close a Scanner is one of those small habits that separates clean, reliable code from programs that silently leak resources or throw unexpected errors.

What Is a Scanner and Why Does Closing It Matter?

The Scanner class in Java (java.util.Scanner) is a utility for parsing input from various sources: System.in, File objects, InputStreams, Strings, and more. Under the hood, a Scanner wraps a readable resource — and when that resource is an open stream or file, it holds onto system-level handles until explicitly released.

Failing to close a Scanner can lead to:

  • Resource leaks — open file handles that persist until the JVM shuts down
  • Locked files — on some operating systems, an unclosed file-backed Scanner can prevent other processes from accessing that file
  • Compiler warnings — many IDEs flag unclosed Scanner instances as a potential issue
  • Unexpected behavior — in long-running applications, accumulated unclosed streams can exhaust available file descriptors

For simple console programs, the JVM will clean up on exit anyway. But for anything reading files, sockets, or running in a server context, closing properly is essential.

The Basic Way to Close a Scanner 🔒

Closing a Scanner is straightforward. The class implements Closeable, which means it has a .close() method:

Scanner scanner = new Scanner(System.in); // ... use the scanner scanner.close(); 

That's it mechanically. But where and how you call .close() is where the real decisions begin.

Using Try-With-Resources (The Recommended Approach)

The cleanest modern approach is the try-with-resources statement, introduced in Java 7. It guarantees the Scanner is closed automatically when the block exits — whether normally or due to an exception:

try (Scanner scanner = new Scanner(new File("data.txt"))) { while (scanner.hasNextLine()) { System.out.println(scanner.nextLine()); } } catch (FileNotFoundException e) { e.printStackTrace(); } 

The Scanner is declared inside the try(...) parentheses. Java handles .close() for you, even if an exception is thrown mid-read. This eliminates an entire category of resource-leak bugs.

When to use this: Anytime your Scanner is scoped to a single method or block. File reading, processing a string, reading from a network stream — try-with-resources fits naturally.

Using Try-Finally (The Pre-Java 7 Pattern)

If you're working in a codebase targeting Java 6 or earlier, or maintaining legacy code, the equivalent pattern uses a finally block:

Scanner scanner = null; try { scanner = new Scanner(new File("data.txt")); while (scanner.hasNextLine()) { System.out.println(scanner.nextLine()); } } catch (FileNotFoundException e) { e.printStackTrace(); } finally { if (scanner != null) { scanner.close(); } } 

The finally block runs regardless of whether an exception occurred, ensuring cleanup. It's more verbose than try-with-resources but functionally equivalent.

The Special Case: Closing a Scanner on System.in ⚠️

This is where many beginners run into trouble. When you create a Scanner wrapping System.in:

Scanner scanner = new Scanner(System.in); 

Closing it also closes System.in itself. Since System.in is a shared, static stream for the entire JVM, closing it means no other part of your program can read from standard input afterward — and it cannot be reopened.

In practice, this matters when:

  • You have multiple classes or methods that all use new Scanner(System.in) at different points
  • Your program reads input in stages, with the Scanner created and destroyed between stages
  • You're writing code that will be called from a larger application or test harness

For short, single-purpose programs where you read all input once and exit, closing System.in-backed scanners is harmless. For larger, modular programs, a common pattern is to create one Scanner for System.in at the application level and pass it through, closing it only at the very end.

Variables That Affect the Right Approach

FactorConsideration
Java versionJava 7+ supports try-with-resources; older code uses try-finally
Input sourceFile/stream scanners should always be closed; System.in requires care
Program scopeShort scripts vs. long-running applications have different risk profiles
ConcurrencyMulti-threaded programs need to coordinate who owns and closes the scanner
Testing environmentUnit tests that close System.in can break subsequent tests in the same suite

What Happens If You Don't Close It

For file-backed Scanners, leaving them open is a genuine problem in any non-trivial program. File handles are a finite OS resource, and in loops or repeated operations, you can exhaust them.

For System.in-backed Scanners in simple command-line programs, the JVM shutdown process releases resources anyway. The risk is low — but your IDE will still warn you, and the habit of not closing is one that scales badly as programs grow.

For String-backed Scanners (new Scanner("some string")), there's no external resource to leak. Closing is technically a no-op, though it's still good practice for consistency.

Checking Before You Use After Closing

Once a Scanner is closed, calling any method on it throws IllegalStateException. If your code architecture involves a Scanner that might already be closed:

// This will throw IllegalStateException if scanner is already closed scanner.nextLine(); 

There's no isOpen() method on Scanner, so defensive programming means either tracking the scanner's lifecycle carefully or restructuring so that closed scanners are never referenced again.


The right closing strategy for a Scanner depends heavily on where it lives in your program's architecture — whether it wraps a file, a console stream, or a string; whether it's scoped tightly to one method or shared across the application; and which Java version your codebase targets. The mechanics are simple, but the implications of when and whether to close ripple into how you structure the rest of your input-handling code.