Search code examples
javaarraylistjava.util.scannernosuchelementexception

NoSuchElementException with ArrayList inside Method


I've got a class called "Player" that's supposed to

  1. set a maximum player amount and
  2. add player names to an ArrayList,

The class looks like this:

public class Player {

    private ArrayList<String> players = new ArrayList<String>();
    private int maxPlayers = 0;


    public ArrayList<String> setPlayers(ArrayList<String> strArrList) {

        Scanner sc = new Scanner(System.in);

        for (int i = 1; i <= getMaxPlayers(); i++) {

            System.out.print("Player #" + i + ": ");
            String name = sc.next();
            strArrList.add(name);
            System.out.println();

        }

        return strArrList;
    }

    public void setMaxPlayers() {

        Scanner sc = new Scanner(System.in);

        System.out.print("How many players? ");
        maxPlayers = sc.nextInt();
        System.out.println();

        sc.close();
    }

    public ArrayList<String> getPlayers() {

        return players;
    }

    public int getMaxPlayers() {

        return maxPlayers;
    }
}

I call on the Player class methods from my Main class like this:

public class Main {

    public static void main(String[] args) {

        Player pl = new Player();

        pl.setMaxPlayers();
        pl.setPlayers(pl.getPlayers());
    }
}

But I get following output:

How many players? 2

Exception in thread "main" java.util.NoSuchElementException
    at java.base/java.util.Scanner.throwFor(Scanner.java:937)
    at java.base/java.util.Scanner.next(Scanner.java:1478)
    at com.arsaii.drinkgame.Player.setPlayers(Player.java:18)
    at com.arsaii.drinkgame.Main.main(Main.java:10)

Process finished with exit code 1

I know what NoSuchElementException means (sort of..) But I've also tried using the same for-loop from the Player class in a different test class inside a main method and it worked.. Does that mean I am getting a NoSuchElementException because it's inside a method.. Could someone explain please..?


Solution

  • The issue is when calling sc.close() in your setMaxPlayers() method. This will close the underlying System.in input stream aswell.

    Due to the fact that System.in has been closed and cannot be reopened, creating another Scanner wrapping System.in in your setPlayers() will fail.

    So the simplest solution, as has also been suggested here, is to simply not close the Scanner instance, if it wraps System.in. Just use one shared Scanner instance and don't close it (at all, or at least if you know you will need it later).