注意:当我们通过java [options] [MainClass] 运行您的代码从 控制台/终端时不会出现问题,因此如果这对您来说是有效的解决方案,您可以在此处停止阅读。此答案的其余部分适用于使用某些 IDE 运行其代码的人。
问题
大多数 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 和Streams 旨在处理 binary 数据,因此它没有可以轻松正确地将数据作为文本读取的方法(特别是如果编码可以参与)。这就是为什么将Readers 和Writers ware 添加到Java 中的原因。
因此,为了让生活更轻松并让应用程序以文本形式从用户读取数据,您可以将此流包装在Readers 之一中,例如BufferedReader,这样您就可以使用readLine() 方法读取整行。不幸的是,这个类不接受Streams,而是Readers,所以我们需要某种适配器,它可以模拟阅读器并能够将字节转换为文本。但这就是 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 和 Reader 中以文本形式读取数据。
这意味着您可以简单地使用
Scanner scanner = new Scanner(System.in);
//...
String name = scanner.nextLine();
从用户那里读取数据(将由IDE使用标准输入流模拟的控制台发送)。