Как получить ввод пользователя в Java

Введение Чтение пользовательского ввода - это первый шаг к написанию полезного программного обеспечения Java. Пользовательский ввод может быть во многих формах - взаимодействие с мышью и клавиатурой, сетевой запрос, аргументы командной строки, файлы, которые обновляются данными, имеющими отношение к выполнению программы, и т. Д. Мы собираемся сосредоточиться на вводе с клавиатуры через так называемый стандарт входной поток. Вы можете узнать его как Java's System.in. Мы собираемся использовать класс Scanner, чтобы упростить наше взаимодействие с базовым потоком. Si

Вступление

Чтение пользовательского ввода - это первый шаг к написанию полезного программного обеспечения Java. Пользовательский ввод может иметь разные формы - взаимодействие с мышью и клавиатурой, сетевой запрос, аргументы командной строки, файлы, которые обновляются данными, имеющими отношение к выполнению программы, и т. Д.

Мы собираемся сосредоточиться на вводе с клавиатуры через так называемый стандартный поток ввода . Вы можете узнать его как Java's System.in .

Мы собираемся использовать Scanner чтобы упростить наше взаимодействие с базовым потоком. Поскольку у Scanner есть некоторые недостатки, мы также будем использовать BufferedReader и InputStreamReader для обработки потока System.in

В конце концов, мы будем Украсьте InputStream класс и реализовать свой собственный пользовательский UncloseableInputStream для решения вопросов с Scanner класса.

Класс Java-сканера

Класс java.util.Scanner - это простой сканер, который может анализировать и обрабатывать примитивные входные данные, строки и потоки. Поскольку System.in - это просто InputStream , мы можем создать Scanner как таковой:

 Scanner sc = new Scanner(System.in); 

Этот Scanner теперь может сканировать и анализировать логические, целые, числа с плавающей запятой, байты и строки.

Давайте посмотрим, как мы можем извлечь информацию из Scanner в переменные, с которыми мы можем работать:

 Scanner sc = new Scanner(System.in); 
 
 // Read an integer into a variable 
 int myInteger = sc.nextInt(); 
 
 // Read a byte into a variable 
 byte myByte = sc.nextByte(); 
 
 // Read a line until newline or EOF into a string 
 String myLine = sc.nextLine(); 
 
 // Closing the scanner 
 sc.close(); 

Опять же, конструктор не должен использовать System.in . Он может принимать любой File , InputStream , Readable , ReadableByteChannel , Path (файла для чтения) или даже String . Кроме того, в качестве второго аргумента он может указать кодировку символов для интерпретации указанных символов:

 Scanner sc = new Scanner(new FileInputStream("myFile.txt"), "UTF-8"); 

Обратите внимание, что Сканер необходимо закрыть, когда вы закончите с ним работать. Самый простой способ сделать это - использовать оператор try-with-resources.

Способы чтения с помощью сканера

Доступные методы чтения следующего токена с помощью метода сканирования:


Методика Тип возврата Описание следующий() Нить Находит и возвращает следующий полный токен со сканера. nextByte () байт Сканирует следующий токен ввода как байт. nextDouble () двойной Сканирует следующий токен ввода как двойной. nextFloat () плавать Сканирует следующий токен ввода как число с плавающей запятой. nextInt () int Сканирует следующий токен ввода как int. nextLong () длинный Сканирует следующий токен ввода как длинный. nextShort () короткая Сканирует следующий токен ввода как короткий. nextBoolean () логический Сканирует следующий токен ввода в логическое значение и возвращает это значение. nextLine () Нить Перемещает этот сканер за пределы текущей строки и возвращает пропущенный ввод.


Стоит отметить метод hasNext() - общий метод, который вернет true если существует какой-либо тип токена для чтения. Существуют методы, зависящие от типа, такие как hasNextInt() , hasNextFloat() , hasNextLine() и т. Д., Которые вы можете использовать таким же образом.

Проблемы при использовании System.in со сканером

Большая проблема с System.in том, что это InputStream . При работе с ним Scanner всегда ожидает большего ввода, пока InputStream будет закрыт. Как только поток будет закрыт, мы больше не сможем получить доступ к вводу со Scanner .

Помимо закрытия самого себя, Scanner также закроет InputStream если он реализует Closeable .

Поскольку InputStream делает это, это означает, что Scanner закроет поток System.in для всей вашей программы .

При этом, если вы закроете Scanner и, следовательно, System.in , вы не сможете снова System.in

 Scanner sc = new Scanner(System.in); 
 System.out.println(sc.nextInt()); 
 sc.close(); 
 System.out.println("Closing the scanner..."); 
 
 sc = new Scanner(System.in); 
 System.out.println(sc.nextInt()); 
 sc.close(); 
 System.out.println("Closing the scanner..."); 

Это приводит к:

 1 
 1 
 Closing the scanner... 
 Exception in thread "main" java.util.NoSuchElementException 
 at java.util.Scanner.throwFor(Scanner.java:862) 
 at java.util.Scanner.next(Scanner.java:1485) 
 at java.util.Scanner.nextInt(Scanner.java:2117) 
 at java.util.Scanner.nextInt(Scanner.java:2076) 
 at com.company.Main.main(Main.java:18) 

Это значительно усложняет работу со Scanner и System.in . Мы исправим это в последнем разделе.

BufferedReader и InputStreamReader

Вместо Scanner вы также можете использовать BufferedReader вместе с InputStreamReader для получения пользовательского ввода:

 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
 
 String line; 
 
 while((line = br.readLine()) != null){ 
 System.out.println(String.format("The input is: %s", line)); 
 } 

Здесь мы просто повторяем входную строку с префиксом:

 Hello! 
 The input is: Hello! 
 I'd like to order some extra large fries. 
 The input is: I'd like to order some extra large fries. 
 ^D 
 
 Process finished with exit code 0 

BufferedReader хорошо подходит для чтения строк, но не имеет встроенных методов для обработки чисел. Чтобы прочитать целое число, вам нужно будет проанализировать его из String:

 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
 
 int a = Integer.parseInt(br.readLine()); 
 System.out.println(a); 

Теперь это отлично работает:

 5 
 5 

Пользовательский Uncloseable InputStream

К счастью, есть решение, как Scanner закрывает поток System.in благодаря шаблону проектирования Decorator . Мы можем реализовать наш собственный InputStream и просто заставить метод close() ничего не делать, чтобы при его Scanner не влиял на базовый стандартный ввод:

 public class UnclosableInputStreamDecorator extends InputStream { 
 
 private final InputStream inputStream; 
 
 public UnclosableInputStreamDecorator(InputStream inputStream) { 
 this.inputStream = inputStream; 
 } 
 
 @Override 
 public int read() throws IOException { 
 return inputStream.read(); 
 } 
 
 @Override 
 public int read(byte[] b) throws IOException { 
 return inputStream.read(b); 
 } 
 
 @Override 
 public int read(byte[] b, int off, int len) throws IOException { 
 return inputStream.read(b, off, len); 
 } 
 
 @Override 
 public long skip(long n) throws IOException { 
 return inputStream.skip(n); 
 } 
 
 @Override 
 public int available() throws IOException { 
 return inputStream.available(); 
 } 
 
 @Override 
 public synchronized void mark(int readlimit) { 
 inputStream.mark(readlimit); 
 } 
 
 @Override 
 public synchronized void reset() throws IOException { 
 inputStream.reset(); 
 } 
 
 @Override 
 public boolean markSupported() { 
 return inputStream.markSupported(); 
 } 
 
 @Override 
 public void close() throws IOException { 
 // Do nothing 
 } 
 } 

Когда мы модифицируем наш проблемный код для использования настраиваемого InputStream , он будет выполняться без проблем:

 public class ScannerDemo { 
 public static void main(String[] args) { 
 
 Scanner sc = new Scanner(new UnclosableInputStreamDecorator(System.in)); 
 System.out.println(sc.nextInt()); 
 sc.close(); 
 System.out.println("Closing the scanner..."); 
 
 sc = new Scanner(new UnclosableInputStreamDecorator(System.in)); 
 System.out.println(sc.nextInt()); 
 sc.close(); 
 System.out.println("Closing the scanner..."); 
 } 
 } 

Выполнение этого приведет к:

 1 
 1 
 Closing the scanner... 
 1 
 1 
 Closing the scanner... 

Заключение

В этой статье мы рассмотрели, как использовать Scanner для чтения пользовательского ввода. Затем мы использовали BufferedReader вместе с InputStreamReader в качестве альтернативного подхода.

Наконец, мы реализовали наш собственный InputStream чтобы избежать того, что Scanner закроет System.in для всей программы.

Надеюсь, вы узнали, как обрабатывать базовый ввод в консоль в Java, и узнали некоторые распространенные ошибки, с которыми вы можете столкнуться в процессе.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus