Почему 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
}