Java

Read a file line by line in Java

Load a text file's lines without the old BufferedReader boilerplate — and stream them when the file is large.

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

public class ReadLines {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("notes.txt");
        List<String> lines = Files.readAllLines(path);
        for (String line : lines) {
            System.out.println(line);
        }
    }
}
Output
// Prints each line of notes.txt to standard output,
// in file order, one line per println.

Open this snippet in the editor

Launches a fresh code space with this Java already loaded — edit it, share the link, or keep building.

The ShareCode editor — write or paste your code, then share the link to bring someone in.
Share a code space by link, QR code, email, social apps, or an embed snippet for your own site.

How it works

`Files.readAllLines` reads the entire file into a `List<String>` in a single call, using UTF-8 by default since Java 18. It replaces the classic `BufferedReader` / `readLine()` loop that needed a try-with-resources block and a null check on every iteration — several lines of ceremony reduced to one expressive call.

Because it returns a `List`, you immediately get a known size, random access, and the ability to stream, sort, or filter the lines afterwards. That convenience is also its boundary: the whole file is materialised in memory at once, so it's meant for configuration files, fixtures, small datasets — inputs that comfortably fit.

For large or unbounded files, stream the lines instead with `Files.lines`. It reads one line at a time and, crucially, returns a stream backed by an open file handle, so it must be used inside try-with-resources to close that handle deterministically. With it you can process a multi-gigabyte log line by line without ever holding it all in memory.

Both methods decode bytes into text, which means charset matters. The modern defaults assume UTF-8; if you're reading a file written in another encoding you'll get garbled characters or a `MalformedInputException`. Pass an explicit `Charset` when the source isn't UTF-8 rather than hoping the platform default matches.

Variations

Stream large files with Files.lines

Process one line at a time and close the handle automatically. This is the right choice whenever the file might be big.

Java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;

public class CountLines {
    public static void main(String[] args) throws IOException {
        try (Stream<String> lines = Files.lines(Path.of("big.log"))) {
            long errors = lines.filter(l -> l.contains("ERROR")).count();
            System.out.println(errors);
        }
    }
}

The classic BufferedReader

Worth recognising in older codebases. It streams like Files.lines but with manual iteration.

Java
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

try (BufferedReader br = Files.newBufferedReader(Path.of("notes.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

Loading config values, skipping comments

A practical use of readAllLines: read a small config file, ignore blank lines and comments, and keep the rest. Because you have the whole List, filtering is a one-liner.

Java
List<String> settings = Files.readAllLines(Path.of("app.conf"))
        .stream()
        .map(String::trim)
        .filter(l -> !l.isEmpty() && !l.startsWith("#"))
        .toList();

Common mistakes & good to know

  • readAllLines loads the entire file into memory. For large or unbounded files use Files.lines and process lazily.
  • Files.lines returns a stream backed by an open file — always use it in try-with-resources or the handle leaks.
  • Decoding assumes UTF-8 by default. Pass an explicit Charset for other encodings, or you'll hit MalformedInputException or garbled text.
  • Both throw NoSuchFileException if the path is wrong — handle or declare the IOException rather than ignoring it.

Frequently asked questions

readAllLines or Files.lines — which should I use?

Use readAllLines when the file is small and you want the whole List. Use Files.lines (in try-with-resources) when the file is large or you only need to scan it once, so you never hold it all in memory.

What charset does it use?

UTF-8 by default in modern Java. If the file uses another encoding, pass an explicit Charset argument or you risk MalformedInputException or corrupted characters.

Do I need to close anything?

readAllLines closes the file itself. Files.lines and BufferedReader return resources backed by an open handle, so wrap them in try-with-resources.

How do I write lines back out?

Files.write(path, listOfLines) is the mirror image of readAllLines, and Files.newBufferedWriter gives you a streaming writer for larger output.

Related snippets

Previous

Group a list of dictionaries by key in Python