Для чого нам потрібен екземпляр класу сканерів, щоб отримати вхід на Java?


10

Java орієнтована на об'єкти, але чому нам потрібно створити об'єкт із класу сканерів, щоб отримати вхід? Не могли next(), наприклад, методи стати просто статичними?

C виглядає на мене досить просто, як ви просто використовуєте scanf(), gets()або fgets(). Я впевнений, що розробникам Java є причина створення класу Scanner, але як це краще, ніж просто мати нормальну функцію для виконання роботи?

Я знайшов це посилання, яке може здатися задавати те саме питання, але відповіді якраз і є

"вам потрібно створити об'єкт, оскільки він не є статичним" ...

Я здогадуюсь: оскільки Java орієнтована на об’єкт, вони вирішили поставити всі методи введення в клас. Вони не робили статичних методів, тому у вас можуть бути різні види різних джерел (клавіатура введення, введення файлів ...) у різних об'єктах?

Буду вдячний, якщо хтось зможе відредагувати питання, щоб зробити його більш зрозумілим!

Відповіді:


34

Відповідь "через те, що сканер має стан".

Дивлячись на коді для java.util.Scanner , ви побачите ряд приватних областей , таких як буфер і пов'язану з ним інформацією, Слічітель, шаблон, джерело вхідного сигналу, інформація про , якщо джерело закритий чи ні, типу останньої відповідності, інформація про те, чи остання річ була дійсною, чи ні, радікс, який використовується для чисел, локал (інформація про те, чи ви використовуєте .або ,як роздільник тисяч), і власний кеш LRU для нещодавно використаних шаблонів , інформація про останній виняток, що трапилася, деяка інформація про розбір чисел, деяка інформація про розбір булевих символів, зовсім трохи більше інформації про розбір цілих чисел ... і я думаю, що про це.

Як бачите, там досить великий блок тексту. Такий стан сканера. Для того, щоб сканер перейшов у статичний клас, цей стан потрібно було б зберігати десь в іншому місці. Спосіб C це робити насправді не має такого стану. У вас є fscanf. ФАЙЛ підтримує деякий стан щодо позиції, в якій він знаходиться (але це потрібно передавати для кожного виклику fscanf). Якщо сталася помилка, ви повинні обробити його (а потім ви починаєте писати код , який виглядає , як це ) - і це не говорить вам інформацію , як «Я очікував Integer, але знайшов String.»

Якщо дивитися на теоретично статичний сканер - весь стан підтримується поза класом, він не інкапсульований у межах класу. Інші біти коду можуть пов'язуватися з цими змінними. Коли інший код може погоджуватися зі станом класу, стає дуже важко міркувати про те, що буде робити клас у будь-якій ситуації.

Ви можете, можливо, написати щось на кшталт ScannerState { Locale loc; ... }і мати код, що призводить до:

ScannerState state = new ScannerState(a whole lot of arguments);
int foo = Scanner.nextInt(state);

Але тоді це набагато громіздкіше, ніж спочатку стан інкапсульований у межах об'єкта Сканера (і не потрібно переходити в стан).

Нарешті, Сканер реалізує інтерфейс, Iterator<String>який означає, що можна використовувати його в такому коді, як:

Scanner in = new Scanner(someFile);
whie(in.hasNext()) { ... }

Не маючи змоги отримати екземпляр класу Scanner, цей тип структури стає більш громіздким в межах об'єктно-орієнтованої мови.


1
Все, що ви написали, абсолютно вірно, хоча InputStream має і стан, і не лише сканер. Якщо вхід надходить з консолі, як на C, вам не потрібно передавати жодні параметри, щоб почати приймати введення. Я припускаю , що це було зроблено таким чином , щоб бути послідовним з тим, як інші потоки , які зробили б вимагають держави.
Ніл

@Neil InputStream прирівнюється до FILE*(стану позиції) в С.
храпового урод

1
Програми сканера Iterator- ні Iterable. Неможливо використовувати Scanner в розширеному циклі.
турбанов

@ratchetfreak Точно. Ось що має мати "state" FileInputStreams, але він не застосовується для введення з консолі, оскільки він уже технічно відкритий.
Ніл

1
@turbanoff Дякую, що зателефонували мені з цього приводу. Я це виправив.

7

коротка відповідь: ти цього не робиш. Ви можете отримати введення користувача без використання екземпляра Scanner.
Наприклад: https://docs.oracle.com/javase/tutorial/essential/io/cl.html або
http://alvinalexander.com/blog/post/java/java-source-code-read-command-line -введення


String orgName = (new BufferedReader(new InputStreamReader(System.in))).readLine();Це жахливо заплутано в порівнянні з використанням A, Scannerа також створює нові екземпляри не одного, а двох об'єктів, щоб відразу відкинути їх.
Філіпп

2
@Philipp, 1) Це громіздко, але це, звичайно, альтернатива, і 2) якщо ви відкидаєте екземпляри відразу, ви робите щось не так (або вам справді потрібно лише прочитати один рядок з консолі).
Артуро Торрес Санчес

Вам не потрібен Сканер для читання вводу. Вам також не потрібен InputStreamReader, і вам не потрібен BufferedReader. Ви можете працювати з "сировинним" потоком на System.in, як і в C. Сканер - це просто дуже зручний спосіб споживання цього потоку.
Traubenfuchs
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.