What is the reason for the JVM handling SIGPIPE the way it does?
I would've expected for
java foo | head -10
with
public class Foo {
public static void main(String[] args){
Stream.iterate(0, n -> n + 1).forEach(System.out::println);
}
}
to cause the process to be killed when writing the 11th line, however that is not the case. Instead, it seems that only a trouble flag is being set at the PrintStream, which can be checked through System.out.checkError().
What happens is that the SIGPIPE exception results in an IOException.
For most
OutputStreamandWriterclasses, this exception propagates through the "write" method, and has to be handled by the caller.However, when you are writing to System.out, you are using a
PrintStream, and that class by design takes care of theIOExceptionof you. As the javadoc says:The above explains what is happening. The "why" is ... I guess ... that the designers wanted to make
PrintStreameasy to use for typical use cases ofSystem.outwhere the caller doesn't want to deal with a possibleIOExceptionon every call.Unfortunately, there is no elegant solution to this:
checkError...FileDescriptor.outobject, and wrap it in a newFileOutputStreamobject ... and use that instead ofSystem.out.Note that there are no strong guarantees that the Java app will only write 10 lines of output in
java foo | head -1. It is quite possible for the app to write-ahead many lines, and to only "see" the pipe closed afterheadhas gotten around to reading the first 10 of them. This applies withSystem.out(andcheckError) or if you wrapFileDescriptor.