I am new to JAVA and could not find yet a way to write a "hello world"-application that works correctly without any change on all platforms and also detects and handles output errors.
In particular, I would like to port the following portable C program to 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;
}
This program is intended to work like this:
$ make
c99 -O hello.c -o hello
$ ./hello
Hello, world!
$ ./hello > /dev/full
An output error occurred.
Unfortunately, I was not yet able to implement the same in JAVA.
Neither System.out.println() nor System.out.flush() seem to check for I/O errors, or maybe I was just not able to catch them.
I already tried to catch exceptions of type IOException, but the compiler tells me that
error: exception IOException is never thrown in body of corresponding try statement
so this is obviously not the right way to do it.
But even if I could find a way to catch output errors, I still had no clue what exit code to use portably, because JAVA does not seem to define something corresponding to C's EXIT_FAILURE.
I find that hard to believe, considering that JAVA is always praised as a highly portable system for application development.
It would be quite shocking if the correct and portable implementation of even a simple "hello world" already exceeded the capabilities of this "write once, run everywhere" platform.
So please help me creating a JAVA implementation that behaves exactly like the C version and is still portable.
Thanks to khelwood and others, I managed to create the following JAVA implementation which works best so far:
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());
}
}
}
However, this is not truly portable because it will only work reliably on POSIX systems which provide a "false" utility.
Otherwise it will revert to the arbitrary return code of 99, which is obviously dangerous because some platform could, for instance, define all negative values as failure codes and all other values as success codes.
System.out
is a PrintStream
.
The docs for PrintStream
say:
Unlike other output streams, a
PrintStream
never throws anIOException
; instead, exceptional situations merely set an internal flag that can be tested via thecheckError
method.
You can check System.out.checkError()
to see if an error has occurred.
If you want your program to exit with a nonzero status, you can use System.exit
.
E.g.
if (System.out.checkError()) {
System.err.println("An output error occurred.");
System.exit(-1);
}
See also Is there a replacement for EXIT_SUCCESS and EXIT_FAILURE in Java?