zoukankan      html  css  js  c++  java
  • 谜题81:烧焦到无法识别

    下面这个程序看起来是在用一种特殊的方法做一件普通的事。那么,它会打印出
    什么呢?

    public class Greeter{
    public static void main(String[] args){
    String greeting = "Hello World";
    for(int i = 0; i < greeting.length(); i++)
    System.out.write(greeting.charAt(i));
    }
    }
    

    尽管这个程序有点奇怪,但是我们没有理由怀疑它会产生不正确的行为。它将
    “Hello World”写入了 System.out,每次写一个字符。你可能会意识到 write
    方法只会使用其输入参数的低位字节(lower-order byte)。所以当“Hello
    World”含有任何外来字符的时候,可能会造成一些麻烦,但这里不会:因为
    “Hello World”完全是由 ASCII 字符组成的。无论你是每次打印一个字符,还
    是一次全部打印,结果都应该是一样的:这个程序应该打印 Hello World。然而,
    如果你运行该程序,就会发现它不会打印任何东西。那句问候语到哪里去了?难
    道是程序认为它并不令人愉快?
    这里的问题在于 System.out 是带有缓冲的。Hello World 中的字符被写入了
    System.out 的缓冲区,但是缓冲区从来都没有被刷新(flush)。大多数的程序
    员认为,当有输出产生的时候 System.out 和 System.err 会自动地进行刷新,这

    并不完全正确。这 2 个流都属于 PrintStream 类型,在 5.0 版[Java-API]中,有
    关这个类型的文档叙述道:
    一个 PrintStream 可以被创建为自动刷新的;这意味着当一个字节数组(byte
    array)被写入,或者某个 println 方法被调用,或者一个换行字符或字节(‘ ’)
    被写入之后,PrintStream 类型的 flush 方法就会被自动地调用。
    System.out 和 System.err 所引用的流确实是 PrintStream 的能够自动刷新的变
    体,但是上面的文档中并没有提及 write(int)方法。有关 write(int)方法的文
    档叙述道:将指定的 byte 写入流。如果这个 byte 是一个换行字符,并且流可以
    自动刷新,那么 flush 方法将被调用[Java-API]。实际上,write(int)是唯一一
    个在自动刷新(automatic flushing)功能开启的情况下不刷新PrintStream的输
    出方法(output method)。
    令人好奇的是,如果这个程序改用 print(char)去替代 write(int),它就会刷新
    System.out 并打印出 Hello World。这种行为与 print(char)的文档是矛盾的,
    因为其文档叙述道[Java-API]:
    打印一个字符:这个字符将根据平台缺省的字符编码方式被翻译成为一个或多个
    字节,并且这些字节将完全按照 write(int)方法的方式被写出。
    类似地,如果程序改用 print(String),它也会对流进行刷新,虽然文档中是禁
    止这么做的。相应的文档确实应该被修改为描述该方法的实际行为,而修改方法
    的行为则会破坏稳定性。
    修改这个程序最简单的方法就是在循环之后加上一个对 System.out.flush 方法
    的调用。经过这样的修改之后,程序就会正常地打印出 Hello World。当然,更
    好的办法是重写这个程序,使用我们更熟悉的 System.out.println 方法在控制
    台上产生输出。
    这个谜题的教训与谜题 23 一样:尽可能使用熟悉的惯用法;如果你不得不使用
    陌生的 API,请一定要参考相关的文档。这里有 3 条教训给 API 的设计者们:请
    让你们的方法的行为能够清晰的反映在方法名上;请清楚而详细地给出这些行为
    的文档;请正确地实现这些行为。

     

  • 相关阅读:
    Android WindowManager和WindowManager.LayoutParams的使用以及实现悬浮窗口的方法
    Android 自定义控件之圆形扩散View(DiffuseView)
    Android线性渐变
    Android Drawable之getIntrinsicWidth()和getIntrinsicHeight()
    Android 用Handler和Message实现计时效果及其中一些疑问
    CentOS6.5下nginx-1.8.1.tar.gz的单节点搭建(图文详解)
    Zeppelin的入门使用系列之创建新的Notebook(一)
    hadoop报错java.io.IOException: Incorrect configuration: namenode address dfs.namenode.servicerpc-address or dfs.namenode.rpc-address is not configured
    ubuntu系统里vi编辑器时,按方向箭头输入是乱码的ABCD字母?(图文详解)
    VirtualBox里如何正确安装增强工具(图文详解)
  • 原文地址:https://www.cnblogs.com/yuyu666/p/9841027.html
Copyright © 2011-2022 走看看