Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this short tutorial, we’ll look at how to handle “NoSuchElementException: No line found” when reading a file using the Scanner class.

First, we’ll understand the root cause of the exception. Then, we’ll learn how to reproduce it in practice and, finally, how to fix it.

2. Understanding the Exception

Scanner, as the name implies, is a Java class that provides methods to scan and parse primitive types and strings.

Among these methods, we find nextLine(), which returns the current line, excluding any line separator at the end.

Before going into the finer points, let’s investigate what “NoSuchElementException: No line found” means.

NoSuchElementException signals that the element we’re trying to access doesn’t exist. Therefore, the stack trace “No line found” indicates that Scanner failed to retrieve the requested line.

The most common cause of this exception is calling the nextLine() method when there’s no line to read.

3. Reproducing the Exception

Now that we know why Scanner fails with NoSuchElementException. Let’s see how to reproduce it.

So, to exemplify the exception, we’ll create a method that uses Scanner.nexLine() to read files:

static String readFileV1(String pathname) throws IOException {
    Path pathFile = Paths.get(pathname);
    if (Files.notExists(pathFile)) {
        return "";
    }

    try (Scanner scanner = new Scanner(pathFile)) {
        return scanner.nextLine();
    }
}

As we can see, we used the Path class to denote the file we want to read.

Now, let’s pass an empty file as a parameter to our method and see what happens:

@Test
void givenEmptyFile_whenUsingReadFileV1_thenThrowException() throws IOException {
    Exception exception = assertThrows(NoSuchElementException.class, () -> {
        ScannerNoSuchElementException.readFileV1("src/test/resources/emptyFile.txt");
    });

    assertEquals("No line found", exception.getMessage());
}

Consequently, attempting to read an empty file leads to NoSuchElementException: No line found.

The main cause here is that nextLine() expects the line to be present. Otherwise, it throws the exception.

4. Solution Using Defensive Programming

The easiest way to avoid the exception is to check if there is a next line before calling nexLine().

To do so, we can use the hasNextLine() method, which returns true if the input has another line.

So, let’s create another method readFileV2() as an enhancement of readFileV1():

static String readFileV2(String pathname) throws IOException {
    Path pathFile = Paths.get(pathname);
    if (Files.notExists(pathFile)) {
        return "";
    }

    try (Scanner scanner = new Scanner(pathFile)) {
        return scanner.hasNextLine() ? scanner.nextLine() : "";
    }
}

As we see above, we return the next line if there is one or an empty string otherwise.

Now, let’s verify that everything works as excepted using a test case:

@Test
void givenEmptyFile_whenUsingReadFileV2_thenSuccess() throws IOException {
    String emptyLine = ScannerNoSuchElementException.readFileV2("src/test/resources/emptyFile.txt");

    assertEquals("", emptyLine);
}

The solution works fine, as demonstrated in the test case. hasNextLine() prevents nexLine() from throwing the exception.

Another solution would be checking if the given file is empty before reading it with Scanner:

static String readFileV3(String pathname) throws IOException {
    Path pathFile = Paths.get(pathname);
    if (Files.notExists(pathFile) || Files.size(pathFile) == 0) {
        return "";
    }

    try (Scanner scanner = new Scanner(pathFile)) {
        return scanner.nextLine();
    }
}

That way, we ensure that at least one line will be consumed by nextLine(). As a consequence, we omitted hasNextLine().

Now, let’s test this new approach:

@Test
void givenEmptyFile_whenUsingReadFileV3_thenSuccess() throws IOException {
    String emptyLine = ScannerNoSuchElementException.readFileV3("src/test/resources/emptyFile.txt");

    assertEquals("", emptyLine);
}

5. Solution Using Exception Handling

Alternatively, we can simply handle NoSuchElementException the traditional way using trycatch blocks:

static String readFileV4(String pathname) throws IOException {
    Path pathFile = Paths.get(pathname);
    if (Files.notExists(pathFile)) {
        return "";
    }

    try (Scanner scanner = new Scanner(pathFile)) {
        return scanner.nextLine();
    } catch (NoSuchElementException exception) {
        return "";
    }
}

As shown above, we caught the exception and returned an empty string.

Lastly, let’s confirm this using a test case:

@Test
void givenEmptyFile_whenUsingReadFileV4_thenSuccess() throws IOException {
    String emptyLine = ScannerNoSuchElementException.readFileV4("src/test/resources/emptyFile.txt");

    assertEquals("", emptyLine);
}

6. Conclusion

In this article, we learned what causes Scanner to throw “NoSuchElementException: No line found” when reading a file.

Then, we understood, using practical examples, how to produce the exception and how to fix it.

As always, the full source code of the examples is available on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are closed on this article!