Dung (Donny) Nguyen

Senior Software Engineer

Input/Output in Java

Input/output, often called I/O, is how a program receives data and shows results. In beginner Java programs, this usually means reading from the keyboard and printing to the console. As you grow, I/O also includes reading from files, writing to files, and working with streams of data.

Console Output

The simplest way to show output is with System.out.println().

System.out.println("Hello, Java!");

println() prints the text and then moves to a new line.

System.out.println("First line");
System.out.println("Second line");

Output:

First line
Second line

Use System.out.print() when you do not want a new line after the output.

System.out.print("Hello, ");
System.out.print("Java!");

Output:

Hello, Java!

Formatted Output

Use System.out.printf() to format values inside a string.

String name = "Alice";
int age = 25;

System.out.printf("Name: %s, Age: %d%n", name, age);

Common format specifiers include:

Specifier Meaning
%s String
%d Integer
%f Floating-point number
%.2f Floating-point number with 2 decimal places
%n New line
double price = 19.987;
System.out.printf("Price: $%.2f%n", price); // Price: $19.99

Console Input with Scanner

The Scanner class is commonly used to read input from the keyboard. It belongs to the java.util package, so you need to import it.

import java.util.Scanner;

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

        System.out.print("Enter your name: ");
        String name = scanner.nextLine();

        System.out.println("Hello, " + name + "!");
    }
}

System.in represents standard input, which is usually the keyboard.

Reading Different Data Types

Scanner provides methods for reading different types of input.

Scanner scanner = new Scanner(System.in);

System.out.print("Enter your age: ");
int age = scanner.nextInt();

System.out.print("Enter your height: ");
double height = scanner.nextDouble();

System.out.print("Are you a student? ");
boolean student = scanner.nextBoolean();

System.out.println("Age: " + age);
System.out.println("Height: " + height);
System.out.println("Student: " + student);

Common Scanner methods include:

Method Reads
next() One word
nextLine() A whole line
nextInt() An int
nextDouble() A double
nextBoolean() A boolean

The nextLine() Issue

A common beginner mistake happens when nextInt(), nextDouble(), or similar methods are followed by nextLine().

Scanner scanner = new Scanner(System.in);

System.out.print("Enter your age: ");
int age = scanner.nextInt();

System.out.print("Enter your name: ");
String name = scanner.nextLine(); // may read the leftover newline

Methods like nextInt() read the number but leave the newline character in the input buffer. The following nextLine() reads that leftover newline instead of waiting for new text.

Fix it by adding an extra nextLine() after reading the number.

Scanner scanner = new Scanner(System.in);

System.out.print("Enter your age: ");
int age = scanner.nextInt();
scanner.nextLine(); // consume the leftover newline

System.out.print("Enter your name: ");
String name = scanner.nextLine();

System.out.println(name + " is " + age + " years old.");

Validating Input

User input can be invalid. Use methods like hasNextInt() to check before reading.

Scanner scanner = new Scanner(System.in);

System.out.print("Enter a number: ");

if (scanner.hasNextInt()) {
    int number = scanner.nextInt();
    System.out.println("You entered: " + number);
} else {
    System.out.println("Invalid number.");
}

For repeated prompting, use a loop.

Scanner scanner = new Scanner(System.in);
int number;

while (true) {
    System.out.print("Enter a number: ");

    if (scanner.hasNextInt()) {
        number = scanner.nextInt();
        break;
    }

    System.out.println("Please enter a valid integer.");
    scanner.nextLine();
}

System.out.println("Number: " + number);

Reading Files

For simple file input, you can use Scanner with a File object.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ReadFileExample {
    public static void main(String[] args) {
        try {
            File file = new File("data.txt");
            Scanner scanner = new Scanner(file);

            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                System.out.println(line);
            }

            scanner.close();
        } catch (FileNotFoundException e) {
            System.out.println("File not found.");
        }
    }
}

Because file operations can fail, Java requires you to handle exceptions such as FileNotFoundException.

Writing Files

Use FileWriter to write text to a file.

import java.io.FileWriter;
import java.io.IOException;

public class WriteFileExample {
    public static void main(String[] args) {
        try {
            FileWriter writer = new FileWriter("output.txt");
            writer.write("Hello, file!\n");
            writer.write("Java can write text files.");
            writer.close();

            System.out.println("File written successfully.");
        } catch (IOException e) {
            System.out.println("An error occurred while writing the file.");
        }
    }
}

By default, FileWriter replaces the file contents. To append instead, pass true as the second argument.

FileWriter writer = new FileWriter("output.txt", true);
writer.write("This line is appended.\n");
writer.close();

Try-With-Resources

When working with files, scanners, readers, writers, or streams, you should close resources after using them. Closing a resource releases the operating system handle behind it. If you forget to close a file, your program may waste memory, lock the file, or fail later because too many files are open.

Without try-with-resources, you must remember to close the resource yourself.

Scanner scanner = null;

try {
    scanner = new Scanner(new File("data.txt"));

    while (scanner.hasNextLine()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException e) {
    System.out.println("File not found.");
} finally {
    if (scanner != null) {
        scanner.close();
    }
}

This works, but it is verbose. Try-with-resources lets you declare the resource inside parentheses after try. Java automatically closes it when the block finishes, whether the code succeeds or throws an exception.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ReadFileExample {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(new File("data.txt"))) {
            while (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            }
        } catch (FileNotFoundException e) {
            System.out.println("File not found.");
        }
    }
}

The syntax is:

try (ResourceType resource = new ResourceType()) {
    // use the resource here
} catch (ExceptionType e) {
    // handle errors here
}

A resource can be used in try-with-resources if its class implements AutoCloseable or Closeable. Many Java I/O classes do, including Scanner, FileReader, BufferedReader, FileWriter, BufferedWriter, and streams.

You can also open multiple resources in the same try statement. Java closes them in reverse order.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyFileExample {
    public static void main(String[] args) {
        try (
            BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
            BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))
        ) {
            String line;

            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine();
            }
        } catch (IOException e) {
            System.out.println("File operation failed.");
        }
    }
}

Use try-with-resources whenever you work with something that must be closed. It keeps the code shorter and helps prevent resource leaks.

Modern File I/O with Files

For many simple tasks, the Files class from java.nio.file is more convenient.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class FilesExample {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("data.txt");

        List<String> lines = Files.readAllLines(path);
        for (String line : lines) {
            System.out.println(line);
        }
    }
}

You can also write lines to a file.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class WriteLinesExample {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("output.txt");
        List<String> lines = List.of("Java", "Input", "Output");

        Files.write(path, lines);
    }
}

Files.readAllLines() is simple, but it loads the whole file into memory. For large files, process lines as a stream.

try (var lines = Files.lines(Path.of("large-file.txt"))) {
    lines.forEach(System.out::println);
}

Common Mistakes

Practice Exercises

  1. Ask the user for their name and age, then print a short introduction.
  2. Ask the user for two numbers and print their sum, difference, product, and quotient.
  3. Keep asking for a number until the user enters a valid integer.
  4. Read a text file and count how many lines it contains.
  5. Write a list of favorite programming languages to a file.

Summary

Input/output lets Java programs communicate with users and external data. Use System.out.print(), println(), and printf() for console output. Use Scanner for beginner-friendly console input, and be careful when mixing token-based methods with nextLine(). For files, older classes like FileWriter still work, but Files and Path provide a modern and convenient way to read and write text.