Java Arena
Step 3 of 9

Reading a file line by line

Here's the program from the previous step again, this time printing each line as it is:

The file plants.txt
basil
mint
rosemary
import java.nio.file.Paths;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(Paths.get("plants.txt"))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                System.out.println(line);
            }
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
}
Output
basil
mint
rosemary

Its parts:

  • Paths.get("plants.txt") turns the file's name into a path, Java's way of pointing to a file. Paths needs its own import at the top: import java.nio.file.Paths;.
  • new Scanner(...) with a path makes a Scanner that reads the file instead of the keyboard (System.in). Its nextLine() works like the keyboard's: each call gives the next line, without the line break at its end.
  • scanner.hasNextLine() works as it did on the keyboard in the first step: it's true until every line has been read, so the loop runs once for each line of the file and then stops.
  • try (...) opens the file for the block after it and closes it when the block ends. A program should close a file when it's done with it, and this form of try, called try-with-resources, does that for you. The Scanner exists only inside the block's braces.
  • catch (Exception e) { ... } is what happens when the reading fails, for example because there's no such file. The next step is about it.

Every round of the loop must call nextLine(). hasNextLine() only looks: if nothing reads the line, the same line stays waiting, hasNextLine() stays true, and the loop never ends.

Keeping the lines in a list

The loop sees each line once. When the program needs the lines afterwards, for example to know how many there are or to use them in another order, it adds them to a list:

The file plants.txt
basil
mint
rosemary
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> plants = new ArrayList<>();
        try (Scanner scanner = new Scanner(Paths.get("plants.txt"))) {
            while (scanner.hasNextLine()) {
                plants.add(scanner.nextLine());
            }
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
        System.out.println("Plants: " + plants.size());
        System.out.println("The last one: " + plants.get(plants.size() - 1));
    }
}
Output
Plants: 3
The last one: rosemary

The list is made before the try, so it still exists after the block. A variable made inside the braces would be gone by then.

A Scanner can read a String too

new Scanner(...) also takes a String, and then reads it as if it were a file. Inside quotes, \n stands for a line break, so the String below holds two lines. A String can't go missing, so no try is needed. It's a quick way to try out a loop, and some of the practice questions use it:

Scanner scanner = new Scanner("first line\nsecond line");
while (scanner.hasNextLine()) {
    System.out.println("> " + scanner.nextLine());
}
Output
> first line
> second line

Your task

Challenge 1 of 3

Fill in the blanks, so the program prints every line of todo.txt with its number in front. For the file shown below, it prints:

1. buy stamps
2. call the dentist
3. water the plants

Challenge 2

The file queue.txt lists the people in a queue, one name per line, from the front of the queue to the back. Print how many people are in the queue, who is first and who is last. The file has at least one name. For the file shown below, the program prints:

In the queue: 4
First: Oona
Last: Tariq

Challenge 3

This program reads a String with a Scanner. What does it print? Look closely at the String: \n is a line break.