java.lang.System快速指南

1.介绍

在本教程中,我们将快速了解java.lang.System类及其特性和核心功能。

2.IO

系统类是java.lang的一部分,它的一个主要特性是让我们能够访问标准的I/O流。

简单地说,它暴露了三个属性,每个流一个:

  • out
  • err
  • in

2.1 System.out

System.out指向标准输出流,将其暴露为PrintStream,我们可以使用它将文本打印到控制台:

System.out.print("This is a test message.");

System的一个高级用法是调用System.setOut,我们可以使用它自定义System.out将写入的位置:

// Redirect to a text file
System.setOut(new PrintStream("filename.txt"));

2.2 System.err

System.err很像System.out。这两个字段都是PrintStream的实例,都用于将消息打印到控制台。

但是System.err代表标准错误,我们专门用它来输出错误消息:

System.err.print("some inline error message");

控制台通常会以不同于输出流的方式呈现错误流。

有关更多信息,请查看 PrintStream 文档。

2.3 System.in

System.in指向中的标准输入,将其暴露为InputStream,我们可以使用它从控制台读取输入。

尽管有点复杂难懂,我们仍然可以这样做:

public String readUsername(int length) throws IOException {
    byte[] name = new byte[length];
    System.in.read(name, 0, length); // by default, from the console
    return new String(name);
}

通过调用System.in.read,应用程序停止并等待标准的输入。无论下一个字节的长度是多少,都将从流中读取并存储在字节数组中。

用户输入的任何其他内容都保留在流中,等待另一个调用读取。

当然,在这样低的级别上操作会很有挑战性,而且容易出错,因此我们可以使用BufferedReader来处理:

public String readUsername() throws IOException {
    BufferedReader reader = new BufferedReader(
      new InputStreamReader(System.in));
    return reader.readLine();
}

按照上面的处理,readLine将从System.in读取,直到用户回车,这种就是我们想要的。

注意,在这种情况下,我们故意不关闭流。关闭的话意味着在程序的生命周期内无法再次读取它!

最后,System.in的一个高级用法是调用System.setIn将其重定向到另一个InputStream。

3.工具方法

系统类还为我们提供了许多方法来帮助我们解决以下问题:

  • 访问控制台

  • 复制数组

  • 观察日期和时间

  • 退出JRE

  • 访问运行时属性

  • 访问环境变量,以及

  • 管理垃圾回收

3.1 访问控制台

Java1.6引入了另一种与控制台交互的方式,而不是直接使用System.out和in。

我们可以通过调用System.console来访问它:

public String readUsername() {
    Console console = System.console();	 	 
	 	 
    return console == null ? null :	 
      console.readLine("%s", "Enter your name: ");	 	 
}

注意,根据底层操作系统和我们如何启动Java来运行当前程序,console可能会返回null,所以在使用之前一定要检查

可以查看控制台文档了解更多用法。

3.2 复制数组

System.arraycopy是一种老式的C风格的方法,可以将一个数组复制到另一个数组中。

arraycopy主要用于将一个完整的数组复制到另一个数组中:

int[] a = {34, 22, 44, 2, 55, 3};
int[] b = new int[a.length];

System.arraycopy(a, 0, b, 0, a.length);
assertArrayEquals(a, b);

但是,我们可以指定两个数组的起始位置,以及要复制多少个元素。

例如,假设我们要从a复制2个元素,从a[1]开始复制到b,从b[3]开始:

System.arraycopy(a, 1, b, 3, 2); 
assertArrayEquals(new int[] {0, 0, 0, 22, 44, 0}, b);

另外,请记住arraycopy将抛出:

  • NullPointerException(如果任一数组为null)

  • 如果副本引用的数组超出其范围,则发生IndexOutOfBoundsException

  • 如果复制导致类型不匹配,则返回ArrayStoreException

3.3 观察日期和时间

系统中有两种与时间相关的方法。一个是currentTimeMillis,另一个是nanoTime。

currentTimeMillis返回自Unix纪元(即1970年1月1日12:00 AM UTC)以来经过的毫秒数:

public long nowPlusOneHour() {
    return System.currentTimeMillis() + 3600 * 1000L;
}

public String nowPrettyPrinted() {
    return new Date(System.currentTimeMillis()).toString();
}

nanoTime返回相对于JVM启动的时间。我们可以多次调用它来标记应用程序中的时间流逝:

long startTime = System.nanoTime();
// ...
long endTime = System.nanoTime();

assertTrue(endTime - startTime < 10000);

请注意,由于nanoTime是如此细粒度,因此执行endTime–startTime<10000比endTime<startTime更安全,因为可能会出现数值溢出。

3.4 退出程序

如果我们想以编程方式退出当前执行的程序,System.exit就可以了。

要调用exit,我们需要指定一个exit代码,它将被发送到启动程序的控制台或shell。

按照Unix中的约定,状态为0表示正常退出,而非0表示发生了一些错误:

if (error) {
    System.exit(1);
} else {
    System.exit(0);
}

请注意,对于现在的大多数程序来说,需要这样称呼是很奇怪的。例如,当在web服务器应用程序中调用时,它可能会关闭整个站点!

3.5 访问运行时属性

系统通过getProperty提供对运行时属性的访问。我们可以用setProperty和clearProperty来管理它们:

public String getJavaVMVendor() {
    System.getProperty("java.vm.vendor");
}
    
System.setProperty("abckey", "abcvaluefoo");
assertEquals("abcvaluefoo", System.getProperty("abckey"));

System.clearProperty("abckey");
assertNull(System.getProperty("abckey"));

通过-D指定的属性可以通过getProperty访问。

我们还可以提供默认值:

System.clearProperty("dbHost");
String myKey = System.getProperty("dbHost", "db.host.com");
assertEquals("db.host.com", myKey);

System.getProperties提供了所有系统属性的集合:

Properties properties = System.getProperties();

从中我们能执行任何Properties操作:

public void clearAllProperties() {
    System.getProperties().clear();
}

3.6 访问环境变量

系统还通过getenv提供对环境变量的只读访问。例如,如果要访问PATH环境变量,可以执行以下操作:

public String getPath() {
    return System.getenv("PATH");
}

3.7 管理垃圾收集

通常,垃圾收集工作对我们的程序来说是不透明的。不过,有时我们可能希望向JVM提出一个直接的建议。 System.runFinalization是一种允许我们建议JVM运行finalization程序的方法。

gc是一种允许我们建议JVM运行其垃圾收集程序的方法。

由于这两种方法的契约不能保证终结或垃圾收集将运行,因此它们的用处很小。

但是,它们可以作为一种优化来使用,比如在桌面应用程序最小化时调用gc:

public void windowStateChanged(WindowEvent event) {
    if ( event == WindowEvent.WINDOW_DEACTIVATED ) {
        System.gc(); // if it ends up running, great!
    }
}
posted @ 2021-06-11 00:01  一锤子技术员  阅读(12)  评论(0编辑  收藏  举报  来源