Ответ «потому что у сканера есть состояние».
Глядя на код для java.util.Scanner , вы увидите ряд закрытых полей, таких как буфер и связанная с ним информация, Matcher, Pattern, источник ввода, информацию о том, закрыт источник или нет, тип из последних найденных совпадений, информация о том, было ли последнее совпадение действительным или нет, основание, используемое для чисел, локаль (информация о том, используете ли вы .
или ,
как разделитель тысяч), и собственный кэш LRU для недавно использованных шаблонов информация о последнем обнаруженном исключении, некоторая информация о разборе чисел, некоторая информация о разборе логических значений, немного больше информации о разборе целых чисел ... и я думаю, вот и все.
Как видите, это довольно большой блок текста. Это состояние сканера. Чтобы превратить сканер в статический класс, это состояние должно быть сохранено где-то еще. Способ C на самом деле не имеет такого большого состояния. Вы получили fscanf
. ФАЙЛ поддерживает некоторое состояние относительно позиции, в которой он находится (но это необходимо передать для каждого вызова fscanf
). Если произошла ошибка, вы должны обработать ее (и затем вы начинаете писать код, который выглядит следующим образом ) - и это не говорит вам о такой информации, как «Я ожидал целое число, но нашел строку».
Если взглянуть на теоретически статический сканер - все состояние поддерживается вне класса, оно не инкапсулировано в классе. Другие биты кода могут повозиться с этими переменными. Когда другой код может повлиять на состояние класса, становится очень трудно рассуждать о том, что класс будет делать в любой конкретной ситуации.
Возможно, вы могли бы написать что-то вроде ScannerState { Locale loc; ... }
и иметь код, который приводит к:
ScannerState state = new ScannerState(a whole lot of arguments);
int foo = Scanner.nextInt(state);
Но тогда это гораздо более громоздко, чем вначале инкапсулировать состояние в объекте Scanner (и не нужно переходить в это состояние).
Наконец, Сканер реализует интерфейс, Iterator<String>
который означает, что его можно использовать в коде, таком как:
Scanner in = new Scanner(someFile);
whie(in.hasNext()) { ... }
Не имея возможности получить экземпляр класса Scanner, этот тип структуры становится более громоздким в объектно-ориентированном языке.