Close

Java 11 - java.io Changes

[Last Updated: Oct 17, 2018]

In this tutorial we will go through new methods of java.io package added in Java 11.

Null InputStream/OutputStream/Reader/Writer

There are situations where we use methods that require InputStream/OutputStream/Reader/Writer parameter and we want to process the parameter transparently even it represents a null input/output stream.

Before Java 11 it was not possible to initialize a stream with null (i.e. creating a stream with disabled input/output) as they throw NullPointerException if null is passed to the corresponding constructor (e.g new FileInputStream(null), new ByteArrayInputStream(null)).

Following new methods have been added which return streams that represent disabled input/output. They read nothing or discard all writes.

java.io.InputStream class:

public static InputStream nullInputStream()

java.io.OutputStream class:

public static OutputStream nullOutputStream()

java.io.Reader class:

public static Reader nullReader()

java.io.Writer class:

public static Writer nullWriter()

All returned streams are initially open.

Calling read()/skip()/transferTo() methods on the returned input streams behave as end of the stream has reached.

Calling write()/append()/flush() methods on the returned output streams do nothing.

After a stream has been closed, calling read/write methods will throw IOException.

Examples

Reading:

public class NullReaderExample {
  public static void main(String[] args) throws IOException {
      Reader reader1 = new StringReader("test string data");
      Reader reader2 = Reader.nullReader();//new method
      Reader reader3 = new CharArrayReader(new char[]{'a', 'b', 'c'});
      printData(List.of(reader1, reader2, reader3));
      reader1.close();
      reader2.close();
      reader3.close();
  }

  public static void printData(List<Reader> readers) {
      readers.stream()
             .map(BufferedReader::new)
             .map(BufferedReader::lines)
             .forEach(stream -> stream.forEach(System.out::println));
  }
}
test string data
abc

Writing:

public class NullWriterExample {
  public static void main(String[] args) throws IOException {
      Writer writer1 = new StringWriter();
      Writer writer2 = Writer.nullWriter();//new method
      Writer writer3 = new CharArrayWriter();
      List<Writer> list = List.of(writer1, writer2, writer3);
      writeData(list);

      //just check the buf content via toString
      list.forEach(writer -> {
          //toString prints underlying data buffer -
          //nullWriter has no buffer and does not override toString
          System.out.printf("writer type: %s, toString: %s%n",
                  writer.getClass().getSimpleName(),
                  writer.toString());
      });
  }

  public static void writeData(List<Writer> writers) throws IOException {
      for (Writer writer : writers) {
          writer.write(Integer.toString(ThreadLocalRandom.current().nextInt()));
          writer.close();
      }
  }
}
writer type: StringWriter, toString: -1912418667
writer type: , toString: java.io.Writer$1@1b0375b3
writer type: CharArrayWriter, toString: -490192658

Before Java 11 same result could be achieved by creating a wrapper class which could ignore all reads and writes. Also see JDK-4358774 and JDK-8196298.

Returning specified bytes with InputStream.readNBytes(int)

public byte[] readNBytes(int len) throws IOException

This method reads up to a specified number of bytes from the input stream.

Example

public class InputStreamReadNBytesExample {
  public static void main(String[] args) throws IOException {
      InputStream stream = new ByteArrayInputStream("test data".getBytes());
      byte[] bytes = stream.readNBytes(4);//new method
      System.out.println(new String(bytes));
      stream.close();
  }
}
test 

The old readNBytes() method:

public int readNBytes(byte[] b, int off, int len) throws IOException

The difference between above old method and the new method is that the old method reads the requested number of bytes from the input stream into the given byte array, whereas the new method returns the specified number of bytes

See also JDK-8139206.

FileReader/FilterWriter new constructors

FileReader and FileWriter have new constructors with additional Charset parameter.

FileReader class:

public FileReader(String fileName, Charset charset)  throws IOException
public FileReader(File file, Charset charset)  throws IOException

FileWriter class

public FileWriter(String fileName, Charset charset) throws IOException
public FileWriter(String fileName, Charset charset, boolean append) throws IOException
public FileWriter(File file, Charset charset) throws IOException
public FileWriter(File file, Charset charset, boolean append) throws IOException

Example

public class FileReaderWriterCharsetExample {
  public static void main(String[] args) throws IOException {
      Path path = Files.createTempFile("test", ".txt");
      File targetFile = path.toFile();
      targetFile.deleteOnExit();

      Charset latinCharset = Charset.forName("ISO-8859-3");
      //FileWriter new constructor
      FileWriter fw = new FileWriter(targetFile, latinCharset);
      fw.write("test filum");
      fw.close();;
      //FileReader new constructor
      FileReader fr = new FileReader(targetFile, latinCharset);
      new BufferedReader(fr).lines().forEach(System.out::println);
      fr.close();
  }
}
test filum

Example Project

Dependencies and Technologies Used:

  • JDK 9.0.1
Java 11 - New methods in java.io package Select All Download
  • java-11-io-changes
    • src
      • com
        • logicbig
          • example
            • NullReaderExample.java

    See Also