Scanner.hasNext: примеры (JAVA)
Scanner.hasNext: booleanОбщее описание метода Scanner.hasNext
Метод hasNext принадлежит классу java.util.Scanner и предназначен для проверки наличия следующего токена в потоке ввода без явного извлечения этого токена. Существует несколько перегрузок, отличающихся по принимаемым аргументам и по способу сопоставления следующего фрагмента ввода.
Подписи основных перегрузок:
boolean hasNext()- возвращает true, если в потоке присутствует следующий токен, обнаруживаемый с учётом текущего разделителя (delimiter).boolean hasNext(Pattern pattern)- возвращает true, если следующий фрагмент ввода соответствует указанному регулярному выражению Pattern. Если pattern равен null, выбрасываетсяNullPointerException.boolean hasNext(String pattern)- компилирует переданную строку в регулярное выражение и проверяет соответствие следующего фрагмента; при передаче null будетNullPointerException.
Дополнительно есть семейство методов для конкретных типов: hasNextInt(), hasNextLong(), hasNextDouble() и т. п. Они проверяют, можно ли следующий токен распарсить в соответствующий примитивный тип с учётом текущей Locale и разделителя.
Ключевые особенности поведения:
- hasNext не удаляет токен из потока; последующий вызов
next()вернёт тот же самый токен, если состояние потока не изменилось. - Проверка может привести к чтению из базового потока ввода и к заполнению внутреннего буфера. При чтении из блокирующих источников (например, System.in, сетевого потока) вызов может блокировать выполнение до получения данных.
- При закрытом Scanner вызывает
IllegalStateExceptionдля большинства операций. - Поведение зависит от текущего разделителя (
useDelimiter), локали (useLocale) и установленного источника ввода.
Возвращаемые значения: всегда boolean. Исключения: IllegalStateException - при закрытом сканере; NullPointerException - при передаче null в перегрузки с шаблоном; чтение из потока может вызвать I/O-исключения внутри реализации (обычно какunchecked).
Короткие примеры использования
Пример 1: базовая проверка наличия токенов
java
import java.util.Scanner;
class A {
public static void main(String[] args) {
Scanner s = new Scanner("one two 3");
System.out.println(s.hasNext());
System.out.println(s.next());
System.out.println(s.hasNextInt());
System.out.println(s.hasNext());
s.close();
}
}
true one false true
Пример 2: hasNext(Pattern) с регулярным выражением
java
import java.util.Scanner;
import java.util.regex.Pattern;
class B {
public static void main(String[] args) {
Scanner s = new Scanner("123 abc");
System.out.println(s.hasNext(Pattern.compile("\\\
\\d+"))); // проверка числового шаблона
System.out.println(s.next());
System.out.println(s.hasNext(Pattern.compile("[a-z]+")));
s.close();
}
}
true 123 true
Пример 3: hasNext с пользовательским разделителем
java
import java.util.Scanner;
class C {
public static void main(String[] args) {
Scanner s = new Scanner("a,b,c");
s.useDelimiter(",");
System.out.println(s.hasNext());
System.out.println(s.next());
System.out.println(s.hasNext());
s.close();
}
}
true a true
Пример 4: hasNext на потоке System.in (блокирующее поведение)
java
import java.util.Scanner;
class D {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("Ожидание ввода...");
boolean b = s.hasNext(); // может блокировать, пока не будет данных или EOF
System.out.println(b);
s.close();
}
}
Ожидание ввода... (true или false в зависимости от ввода и EOF)
Похожие средства в Java и их особенности
hasNextInt/hasNextDouble/hasNextLong- проверяют конкретный примитивный тип и полезны, когда требуется гарантированная проверка парсинга без дополнительной логики.hasNextLine()- проверяет наличие следующей строки, отличается от hasNext тем, что оперирует границами строки, а не токенами.findInLine/ findWithinHorizon- возвращают найденную подстроку по регулярному выражению и удобны для поиска в пределах строки или окна; используются при более сложном парсинге с позиционированием.BufferedReader.readLine()- альтернатива при построчном чтении больших объёмов, предпочтительна по производительности и простоте для чтения строк целиком.StreamTokenizer- устаревший инструмент для токенизации с более детальным управлением синтаксисом.
Выбор зависит от задач: Scanner удобен для быстрого токен-ориентированного разбора; BufferedReader подходит для потокового считывания больших текстов и построчной обработки; специализированные средства (регулярные выражения, парсеры CSV/JSON) предпочтительнее для сложных форматов.
Эквиваленты в других языках и отличия
Python
python
s = "1 two 3"
it = iter(s.split())
try:
v = next(it)
print(True, v)
except StopIteration:
print(False)
True 1
Комментарий: в Python нет прямого hasNext; используется итератор и обработка StopIteration или проверка наличия элементов в списке.
JavaScript (ES6 итератор)
javascript
const arr = "a b".split(' ');
const it = arr[Symbol.iterator]();
console.log(it.next());
console.log(it.next().done);
{ value: 'a', done: false }
false
Комментарий: в JS есть поле done в возвращаемом объекте, аналог boolean hasNext.
C#
csharp
using System.IO;
var sr = new StreamReader(new MemoryStream(System.Text.Encoding.UTF8.GetBytes("x\ny")));
int p = sr.Peek();
Console.WriteLine(p != -1);
True
Комментарий: StreamReader.Peek возвращает -1 при EOF, что аналогично проверке наличия следующего символа.
Go
go
package main
import (
"bufio"
"fmt"
"strings"
)
func main(){
s := bufio.NewScanner(strings.NewReader("one two"))
for s.Scan() {
fmt.Println("has token:", s.Text())
}
}
has token: one has token: two
Комментарий: bufio.Scanner.Scan() возвращает bool, похож на hasNext+next.
PHP
php
<?
$fp = fopen('php://memory','r+');
fwrite($fp, "line\n");
rewind($fp);
var_dump(!feof($fp));
?>
bool(true)
Комментарий: в PHP feof проверяет конец потока, но прямого аналога token-ориентированного hasNext нет.
Lua
lua
local s = io.open("test.txt","r")
local line = s:read()
if line then print(true, line) else print(false) end
s:close()
true (содержимое первой строки)
Kotlin
kotlin
import java.util.Scanner
fun main(){
val s = Scanner("7 eight")
println(s.hasNext())
}
true
Комментарий: Kotlin использует тот же java.util.Scanner на JVM; поведение совпадает с Java.
SQL / JDBC
java
// ResultSet rs = stmt.executeQuery(...);
// boolean has = rs.next(); // переход к первой строке, возвращает true если есть
(true/false в зависимости от результата)
Комментарий: JDBC возвращает boolean из next(), но при этом курсор продвигается - отличие от hasNext, который не должен продвигать токен в Scanner.
Типичные ошибки и демонстрации
Ошибка 1: ожидание, что hasNextInt сразу потребует удаления токена
java
import java.util.Scanner;
class E{
public static void main(String[] a){
Scanner s = new Scanner("10 20");
System.out.println(s.hasNextInt());
System.out.println(s.next()); // вернёт "10", потому что hasNextInt не удалил токен
}
}
true 10
Ошибка 2: использование hasNext после закрытия Scanner
java
import java.util.Scanner;
class F{
public static void main(String[] a){
Scanner s = new Scanner("x");
s.close();
System.out.println(s.hasNext());
}
}
Exception in thread "main" java.lang.IllegalStateException: Scanner closed ...
Ошибка 3: передача null в hasNext(Pattern)
java
import java.util.Scanner;
import java.util.regex.Pattern;
class G{
public static void main(String[] a){
Scanner s = new Scanner("n");
Pattern p = null;
System.out.println(s.hasNext(p));
}
}
Exception in thread "main" java.lang.NullPointerException ...
Ошибка 4: блокировка при чтении из System.in
java
import java.util.Scanner;
class H{
public static void main(String[] a){
Scanner s = new Scanner(System.in);
System.out.println(s.hasNext()); // если нет EOF и вход не введён, выполнение будет ждать
}
}
(программа может висеть, ожидая ввода)
Изменения в реализации и совместимость
Класс Scanner был введён в Java 5 (JDK 1.5) и с тех пор сохраняет ту же публичную сигнатуру методов hasNext и его перегрузок. Встречаются внутренние оптимизации реализации в разных релизах JDK, однако API остаётся обратнозаменяемым. Для большинства проектов значимых изменений в поведении hasNext в последних версиях не отмечено.
Продвинутые и нестандартные примеры применения
Пример 1: разбор CSV с простым учётом разделителя и проверкой следующего поля
java
import java.util.Scanner;
import java.util.regex.Pattern;
class CSVParser{
public static void main(String[] args){
String csv = "one,2,three,4";
Scanner s = new Scanner(csv);
s.useDelimiter(",");
while(s.hasNext()){
if(s.hasNext(Pattern.compile("\\d+"))){
System.out.println("Number:"+s.next());
} else {
System.out.println("Text:"+s.next());
}
}
s.close();
}
}
Text:one Number:2 Text:three Number:4
Пояснение: hasNext(Pattern) позволяет условно выбирать обработчик для следующего поля без предварительного извлечения строки.
Пример 2: использование локали для проверки чисел с запятой
java
import java.util.Scanner;
import java.util.Locale;
class LocaleExample{
public static void main(String[] args){
Scanner s = new Scanner("3,14 2.71");
s.useLocale(Locale.FRANCE); // во Франции десятичный разделитель - запятая
System.out.println(s.hasNextDouble());
System.out.println(s.nextDouble());
System.out.println(s.hasNextDouble());
System.out.println(s.nextDouble());
s.close();
}
}
true 3.14 true 2.71
Пояснение: locale влияет на парсинг чисел hasNextDouble и nextDouble.
Пример 3: использование findWithinHorizon для сложного поиска (альтернатива hasNext с шаблоном)
java
import java.util.Scanner;
class FindExample{
public static void main(String[] args){
Scanner s = new Scanner("id:123; name:abc; id:456");
String found;
while((found = s.findWithinHorizon("id:(\\\\d+)", 0)) != null){
System.out.println("Found id -> "+found);
}
s.close();
}
}
Found id -> id:123 Found id -> id:456
Пояснение: findWithinHorizon возвращает найденную подстроку и полезен, если требуется получить совпадение и одновременно продвинуть позицию.
Пример 4: аккуратная работа с newline при смешанном использовании nextInt и nextLine
java
import java.util.Scanner;
class NextMix{
public static void main(String[] args){
Scanner s = new Scanner("10\nrest of line\n");
if(s.hasNextInt()){
int n = s.nextInt();
s.nextLine(); // поглощение остатка строки после nextInt
System.out.println(n);
System.out.println(s.nextLine());
}
s.close();
}
}
10 rest of line
Пояснение: nextInt оставляет символ перевода строки, поэтому для корректного перехода к следующей строке используется дополнительный nextLine.