Scanner.hasNext: примеры (JAVA)

Scanner.hasNext - справочная заметка и примеры
Раздел: Сканирование ввода (Scanner)
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
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
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
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
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.

джава Scanner.hasNext function comments

En
Scanner.hasNext Returns true if this scanner has another token in its input