是否可以在 JAVA 中编写正确且可移植的控制台输出 "hello world"?

Is it possible to write a correct and portable console-output "hello world" in JAVA?

我是 JAVA 的新手,还没有找到编写 "hello world" 应用程序的方法,该应用程序无需任何更改即可在所有平台上正常工作,并且还可以检测和处理输出错误。

特别是,我想将以下可移植 C 程序移植到 JAVA:

"Makefile":

.POSIX:

TARGETS = hello

.PHONY: all clean

all: $(TARGETS)

clean:
    -rm $(TARGETS)

"hello.c":

#include <stdio.h>
#include <stdlib.h>

int main(void) {
   if (puts("Hello, world!") >= 0 && fflush(0) == 0) return EXIT_SUCCESS;
   (void)fputs("An output error occurred.\n", stderr);
   return EXIT_FAILURE;
}

此程序旨在像这样工作:

$ make
c99 -O    hello.c   -o hello

$ ./hello
Hello, world!

$ ./hello > /dev/full
An output error occurred.

不幸的是,我还不能在 JAVA 中实现相同的功能。

System.out.println() 和 System.out.flush() 似乎都没有检查 I/O 错误,或者我只是没能发现它们。

我已经尝试捕获 IOException 类型的异常,但编译器告诉我

error: exception IOException is never thrown in body of corresponding try statement

所以这显然不是正确的方法。

但即使我能找到一种方法来捕获输出错误,我仍然不知道可移植地使用什么退出代码,因为 JAVA 似乎没有定义与 C 的 EXIT_FAILURE 相对应的东西.

我很难相信,考虑到 JAVA 一直被誉为应用程序开发的高度可移植系统。

如果即使是一个简单的 "hello world" 的正确和可移植的实现已经超过了这个 "write once, run everywhere" 平台的能力,那将是非常令人震惊的。

所以请帮我创建一个 JAVA 实现,它的行为与 C 版本完全一样,并且仍然可移植。

感谢 khelwood 和其他人,我设法创建了以下 JAVA 目前效果最好的实现:

public class HelloWorld {
   private static class OutputError extends java.io.IOException { }

   private static void println(String s) throws OutputError {
      System.out.println(s);
      if (System.out.checkError()) throw new OutputError();
   }

   private static void flush() throws OutputError {
      System.out.flush();
      if (System.out.checkError()) throw new OutputError();
   }

   private static int getExitFailureCode() {
      try {
         return (new java.lang.ProcessBuilder("/bin/false")).start().waitFor();
      } catch (Exception dummy) {
         return 99;
      }
   }

   public static void main(String[] args) {
      try {
         println("Hello, world!");
         flush();
      } catch (OutputError dummy) {
         System.err.println("An output error occurred.");
         System.exit(getExitFailureCode());
      }
   }
}

但是,这并不是真正的可移植,因为它只能在提供 "false" 实用程序的 POSIX 系统上可靠地工作。

否则它将恢复为任意 return 代码 99,这显然是危险的,因为某些平台可能会,例如,将所有负值定义为失败代码,将所有其他值定义为成功代码。

对象 System.outjava.io.PrintStream 的实例。您可以使用 checkError() 检查可能的错误。

System.outPrintStream.

PrintStream 的文档说:

Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method.

您可以检查 System.out.checkError() 以查看是否发生了错误。

如果你想让你的程序以非零状态退出,你可以使用System.exit.

例如

if (System.out.checkError()) {
    System.err.println("An output error occurred.");
    System.exit(-1);
}

另见 Is there a replacement for EXIT_SUCCESS and EXIT_FAILURE in Java?