Почему hasNextLine() никогда не заканчивается?

Извините, если это звучит слишком просто. Я очень новичок в Java.

Вот простой код, который я использовал для изучения hasNextLine(). Когда я запускаю его, я не могу остановить его. Я думал, что если вы не ввели никакой ввод и нажали Enter, вы бы избежали цикла while.

Может кто-нибудь объяснить мне, как hasNextLine() работает в этой ситуации?

import java.util.*;

public class StringRaw {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNextLine()) {
            String str = sc.nextLine();
        }
        System.out.print("YOU'VE GOT THROUGH");
    }
}

Ответ 1

Когда вы читаете System.in, вы читаете с клавиатуры по умолчанию, и это бесконечный поток ввода... он имеет столько строк, сколько пользователь должен печатать. Я думаю, что отправка управляющей последовательности для EOF может работать, например CTL-Z (или это CTL-D?).

Глядя на мою диаграмму AOLII хорошего кода... CTL-C - это ETX, а CTL-D - EOT; любой из них должен работать, чтобы прервать текстовый поток. CTL-Z - это SUB, который не должен работать (но он может, поскольку элементы управления исторически интерпретируются очень субъективно).

Ответ 2

Нажмите Ctrl + D, чтобы завершить ввод из stdin. (Windows: Ctrl + Z) или введите ввод из команды:

echo -e "abc\ndef" | java Program

Ответ 3

CTRL-D - это конец символьного или байтового потока для UNIX/Linux, а CTRL-Z - конец символьного или байтового потока для Windows (исторический артефакт с самых ранних дней Microsoft DOS).

С кодом вопроса, как написано, пустая строка не выйдет из цикла, потому что hasNextLine() не будет оценивать значение false. Он будет иметь терминатор линии во входном байтовом потоке.

System.in - это поток байтов со стандартного ввода, обычно консоль. Поэтому прекращение потока байтов останавливает цикл. Хотя nextLine() не блокирует ожидание ввода, hasNextLine() делает. Единственный способ, которым код заканчивается, в том виде, как он был разработан, - с CTRL-Z в Windows или CTRL-D в UNIX/Linux, который заканчивает поток байтов, вызывает hasNextLine(), чтобы не блокировать ожидание ввода и возвращать логическое значение false, которое завершается цикл while.

Если вы хотите, чтобы он завершился с пустым вводом строки, вы можете проверить непустые строки как часть условия продолжения цикла. Следующий код демонстрирует, как изменить базовый дизайн вопроса, который использует hasNextLine() и nextLine() для того, который завершает работу, если он получает пустую строку или конец входного символа (т.е. CTRL-Z в Windows или CTRL-D в UNIX/Linux). Дополнительный код в условии while использует функцию операторов присваивания, в которой они могут быть оценены как выражение для возврата назначенного значения. Поскольку это объект String, метод String.equals() может использоваться с оценкой.

Другой дополнительный код просто добавляет некоторый печатный результат, чтобы сделать то, что происходит очевидным.

// HasNextLineEndDemo.java
import java.util.*;

public class HasNextLineEndDemo {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // this code is a bit gee-whiz
        // the assignment expression gets assigned sc.nextLine()
        // only if there is one because of the &&
        // if hasNextLine() is false, everything after the &&
        // gets ignored
        // in addition, the assignment operator itself, if
        // executed, returns, just like a method return,
        // whatever was assigned to str which, 
        // as a String object, can be tested to see if it is empty
        // using the String.equals() method
        int i = 1; // input line counter
        String str = " "; // have to seed this to other than ""
        System.out.printf("Input line %d: ", i); // prompt user
        while (sc.hasNextLine() && !(str = sc.nextLine()).equals("")) {
            System.out.printf("Line %d: ", i);
            System.out.println("'" + str + "'");
            System.out.printf("Input line %d: ", ++i);
        } // end while
        System.out.println("\nYOU'VE GOT THROUGH");
    } // end main
} // end class HasNextLineEndDemo

Ответ 4

Насколько я понимаю, если вы возьмете пример объекта набора результатов из JDBC или любого итератора, то в этих случаях у вас будет конечный набор вещей, и итераторы каждый раз проверяют, достигнут ли конец набора. Однако в приведенном выше случае они не могут узнать конец пользовательского ввода, то есть hasNextLine() не может узнать, когда пользователь хочет завершить работу, и, следовательно, он продолжается бесконечно. Лучший способ - это поместить дополнительное условие в цикл for, который проверяет некоторое условие внутри цикла for, который завершится неудачей в будущем. В приведенном выше посте ответ @Jim иллюстрирует это.

Фактически, использование hasNextLine() в качестве ограничителя цикла для ввода с консоли не рекомендуется, поскольку оно никогда не вернет false.

Ответ 5

У меня была похожая проблема с входным потоком сокета. Большинство решений, которые я нашел, по-прежнему блокируют выполнение. Оказывается, есть не блокирующая проверка, которую вы можете сделать с InputStream.available(). Так что в этом случае должно работать следующее:

int x = System.in.available();
if (x!=0) {
    //Your code
}