Ответ 1
Проблема
Большинство IDE используют javaw.exe
вместо java.exe
для запуска Java-кода (см. рисунок ниже).
Разница между этими двумя программами заключается в том, что javaw
запускает код Java без связи с текущим терминалом/консолью (что полезно для приложений GUI), и поскольку нет связанного окна консоли System.console()
возвращает null
. Из-за этого System.console().readLine()
заканчивается как null.readLine()
, который выдает NullPointerException
, так как null
не имеет метода readLine()
(и никакого метода/поля).
Но только потому, что нет связанной консоли, это не значит, что мы не можем общаться с процессом javaw
. Этот процесс по-прежнему поддерживает стандартные потоки ввода/вывода/ошибок, поэтому процесс IDE (и через него также мы) может использовать их через System.in
, System.out
и System.err
.
Таким образом, IDE могут иметь некоторую вкладку/окно и позволить имитировать консоль.
Например, когда мы запускаем код, как в Eclipse:
package com.stackoverflow;
public class Demo {
public static void main(String[] args) throws Exception {
System.out.println("hello world");
System.out.println(System.console());
}
}
мы увидим как результат
который показывает, что несмотря на то, что javaw.exe
не имеет связанной консоли (null
в конце), IDE смогла обработать данные из стандартного вывода процесса javaw
System.out.println("hello world");
и показать hello world
.
Общее решение
Чтобы пользователь мог передавать информацию для обработки, используйте стандартный поток ввода (System.in
). Но так как in
прост InputStream
и Stream
предназначены для обработки двоичных данных, у него нет методов, которые позволяли бы ему легко и правильно читать данные в виде текста (особенно если кодирование может быть задействовано). Вот почему Readers
и Writers
ware добавлены в Java.
Итак, чтобы облегчить жизнь и позволить программе читать данные от пользователя в виде текста, вы можете обернуть этот поток в один из Reader
, как BufferedReader
, который позволит вам прочитать целую строку с помощью метода readLine()
. К сожалению, этот класс не принимает Streams
, но Reader
s, поэтому нам нужен какой-то адаптер, который будет имитировать Reader и сможет переводить байты в текст. Но вот почему InputStreamReader
существует.
Таким образом, код, который позволит приложениям считывать данные из входного потока, может выглядеть как
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Hello. Please write your name: ");
String name = br.readLine();
System.out.println("Your name is: "+name);
Предпочтительное/простейшее решение - Сканер
Чтобы избежать этой магии, связанной с преобразованием Stream в Reader, вы можете использовать класс Scanner
, который предназначен для чтения данных в виде текста из Streams and Readers.
Это означает, что вы можете просто использовать
Scanner scanner = new Scanner(System.in);
//...
String name = scanner.nextLine();
для чтения данных от пользователя (которые будут отправляться с помощью консоли, моделируемой IDE, с использованием стандартного потока ввода).