最近看到一篇挺有意思的文章,国外一程序员发现,很多语言实现的 Hello World 程序都有 Bug。
比如在Java中,Hello World一般是:
class hello{
public static void main(String[] args){
System.out.println("hello world");
}
}
正常情况下运行如下:
$ javac hello.java
$ java hello
hello world
但如果我们将它重定向输出到/dev/full
文件:
/dev/full
:满设备。任何写入都将失败,并把errno设为ENOSPC(没有剩余空间)
$ java hello > /dev/full
可以看到程序没有任何输出,查看程序返回值:
$ echo $?
0
此时发现程序返回0,说明并没有报错。
然而我们知道程序重定向输出到/dev/full
肯定是报错的,而返回值却显示没有报错,因此就有bug。
究其原因,是因为在输出流System.out.println("hello world");
中,即使报错了也不会抛出异常,
A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Two other features are provided as well. 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.
PrintStream为另一个输出流添加了功能,即能够方便地打印各种数据值的表示。还提供了另外两个功能。与其他输出流不同,PrintStream从不抛出IOException;相反,异常情况只是设置了一个内部标志,可以通过checkError方法进行测试。
也就是说System.out.println("hello world");
输出之后,永远不会抛出IO异常,需要手动通过checkError
去判断有没有报错,于是改进如下:
class hello{
public static void main(String[] args){
System.out.println("hello");
boolean hasError = System.out.checkError();
if(hasError){
System.exit(1);
}
}
}
运行程序:
$ javac hello.java
$ java hello
hello
$ java hello > /dev/full
$ echo $?
1
可以看到改进后的代码重定向输出到/dev/full
后正确报错了。
所以开发的时候最好不要用System.out.println()
输出,即使用也要判断一下输出后有没有报错,不然可能程序报错了也不知道。
事实上不止Java有这个问题,很多语言都有,原作者还测试了其他语言,C、C++、Go都有这个问题,详见:https://github.com/sunfishcode/hello-world-vs-io-errors