Scanner в Java NoSuchElementException

import java.util.InputMismatchException;
import java.util.Scanner;

public class Main {
    public static void main (String[] args){
        boolean flag = true;

        do {
            System.out.println("Введите комманду(add|list|quit|change): ");
            try(Scanner scanner = new Scanner(System.in)){
                String com;
                com = scanner.nextLine().toLowerCase().trim();
                switch (com) {
                    case "add":
                        //тут добавление
                        break;
                    case "list":
                        //тут список
                        break;
                    case "quit":
                        flag = false;
                        break;
                    case "change":
                        //тут редактирование
                        break;
                    default:
                        System.out.println("Не верная комманда!");
                        scanner.close();
                        break;
                }
            }catch (Exception e){
                System.out.println("Вы ввели не верную команду: " + e);
            }
        }while (flag);
    }
}

При попадании в ветку default он больше не пытается считать новую строку из консоли и постоянно валится в ветку catch с ошибкой java.util.NoSuchElementException: No line found, хотя он не предлагает ввести новую строку. Подскажите как его заставить считать новую строку.


Ответы (1 шт):

Автор решения: Alexey R.

Поместите do внутрь try-catch блока, а не наоборот. Сканнер закрывать не обязательно. Т.к. вы используете синтаксис "try-with-resource", сканнер сам закроется при выходе из блока.

Почему в коде вопроса проблема

Дело в том, что Scanner закрываясь, каскадно закрывает низлежащие стримы, в том числе и System.in. Поэтому, дальнейшие сканнеры, основанные на этом стриме будут вызывать ексепшены. Вот коороткое демо:

Это как бы наш сканер:

class ExampleClosable implements AutoCloseable{

    @Override
    public void close() throws Exception {
        System.out.println("This instance closed.");
    }
}

А это наш трай-кетч внутри цикла:

public class Main {
    public static void main(String[] args) {
        for(int i = 0; i < 2; i++){
            try(ExampleClosable exampleClosable = new ExampleClosable()){
                System.out.println("Loop body..");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Что приводит к выводу:

Loop body..
This instance closed.
Loop body..
This instance closed.

Т.е. при завершении первой итерации цикла, сканер закрывается, что приводит к закрытию System.in, что приводит к дальнейшим ексепшенам.

→ Ссылка