Java 没有在SIGPIPE上杀死JVM

Java 没有在SIGPIPE上杀死JVM,java,jvm,signals,sigpipe,Java,Jvm,Signals,Sigpipe,JVM以这种方式处理SIGPIPE的原因是什么 我早就料到了 javafoo | head-10 与 公共类Foo{ 公共静态void main(字符串[]args){ Stream.iterate(0,n->n+1).forEach(System.out::println); } } 在写入第11行时导致进程终止,但情况并非如此。相反,似乎在PrintStream上只设置了一个故障标志,可以通过System.out.checkError()检查,结果是SIGPIPE异常导致IOExcept

JVM以这种方式处理SIGPIPE的原因是什么

我早就料到了

javafoo | head-10

公共类Foo{
公共静态void main(字符串[]args){
Stream.iterate(0,n->n+1).forEach(System.out::println);
}
}

在写入第11行时导致进程终止,但情况并非如此。相反,似乎在PrintStream上只设置了一个
故障
标志,可以通过
System.out.checkError()

检查,结果是SIGPIPE异常导致IOException

对于大多数
OutputStream
Writer
类,此异常通过“write”方法传播,必须由调用方处理

但是,当您写入System.out时,您使用的是一个
PrintStream
,该类按设计负责处理您的
IOException
。正如javadoc所说:

PrintStream
为另一个输出流添加了功能,即能够方便地打印各种数据值的表示。还提供了另外两个特性。与其他输出流不同,
PrintStream
从不抛出
IOException
;相反,异常情况只是设置了一个内部标志,可以通过
checkError
方法进行测试

JVM以这种方式处理SIGPIPE的原因是什么

以上解释了正在发生的事情。“为什么”是。。。我想。。。设计者希望使
PrintStream
易于用于
System.out
的典型用例,调用方不希望在每次调用时处理可能的
IOException

不幸的是,没有优雅的解决方案:

  • 您可以直接调用
    checkError
  • 您应该能够获得
    FileDescriptor.out
    对象,并将其包装到一个新的
    FileOutputStream
    对象中。。。并用它代替
    System.out


请注意,Java应用程序在
JavaFoo | head-1
中只能写入10行输出,这一点并没有强有力的保证。应用程序很可能会提前写很多行,并且只有在
head
开始阅读前10行之后才能“看到”关闭的管道。这适用于
System.out
(和
checkError
),或者如果包装
FileDescriptor
,,则会发生SIGPIPE异常导致IOException

对于大多数
OutputStream
Writer
类,此异常通过“write”方法传播,必须由调用方处理

但是,当您写入System.out时,您使用的是一个
PrintStream
,该类按设计负责处理您的
IOException
。正如javadoc所说:

PrintStream
为另一个输出流添加了功能,即能够方便地打印各种数据值的表示。还提供了另外两个特性。与其他输出流不同,
PrintStream
从不抛出
IOException
;相反,异常情况只是设置了一个内部标志,可以通过
checkError
方法进行测试

JVM以这种方式处理SIGPIPE的原因是什么

以上解释了正在发生的事情。“为什么”是。。。我想。。。设计者希望使
PrintStream
易于用于
System.out
的典型用例,调用方不希望在每次调用时处理可能的
IOException

不幸的是,没有优雅的解决方案:

  • 您可以直接调用
    checkError
  • 您应该能够获得
    FileDescriptor.out
    对象,并将其包装到一个新的
    FileOutputStream
    对象中。。。并用它代替
    System.out


请注意,Java应用程序在
JavaFoo | head-1
中只能写入10行输出,这一点并没有强有力的保证。应用程序很可能会提前写很多行,并且只有在
head
开始阅读前10行之后才能“看到”关闭的管道。这适用于
System.out
(和
checkError
)或如果您包装
FileDescriptor

,谢谢您的回答。这种推理是有道理的。。在大多数用例中,每当管道出现问题时,处理IOException可能会很烦人。使用
FileDescriptor
的方法似乎是一种优雅的方法,如果您喜欢这种行为,请告诉我它是否有效。我还没试过。我通过查看
系统
类中发生的事情来了解它。。。我可能弄错了。(我>>认为当你想写stdout时,你需要
FileDescriptor.out
。一般来说,
PrintStream
是一个可怕的错误设计,但与其他Java 1.0错误不同,它没有被弃用,因为它在
系统.out
字段中的突出位置。这似乎是可能的,是的。我想最好是这样被包装在自定义打印流中,然后在IOException中退出。@leyren
PrintStream
OutputStream
的子类型,混淆了字节流和字符流的概念。类似的错误设计的类,例如
LineNumberInputStream
StringBufferInputStream
,已被弃用。as说,
PrintStream
由于兼容性问题,
PrintWriter
没有被替换,因为
System.out
无法更改。但即使是替换者也有吞咽异常的可怕行为,只告诉发生了异常(一个
布尔值)