Java I/O Annoyances

While making some code updates the other day, I discovered a couple of potentially confusing features of the package that I wasn't previously aware of:

  1. The PrintStream and PrintWriter classes consume exceptions. From the PrintWriter documentation:

    Methods in this class never throw I/O exceptions, although some of its constructors may. The client may inquire as to whether any errors have occurred by invoking checkError().

    Because I had incorrectly assumed that a PrintWriter would propagate any exceptions thrown by the underlying stream, I hadn't been calling checkError(). The result was that my servlet class, which was using the print writer returned by ServletResponse#getWriter(), failed to detect when a connection had been terminated by the client. The servlet simply continued writing to the output stream. Once I started calling checkError(), the response was correctly terminated:

    if (writer.checkError()) {
        throw new IOException("Error writing to output stream.");

    I couldn't find any explanation as to why these two classes were written this way, while all of the other classes in appear to simply propagate exceptions.

  2. The read(byte[], int, int) method of the InputStream class also consumes exceptions. From the Javadoc:

    The read(b, off, len) method for class InputStream simply calls the method read() repeatedly. If the first such call results in an IOException, that exception is returned from the call to the read(b, off, len) method. If any subsequent call to read() results in a IOException, the exception is caught and treated as if it were end of file.

    This is extremely misleading, since it completely obscures the fact that an error occurred and makes it appear as though the stream terminated normally.

So, even though this behavior is not what I had expected, at least it is documented, and is something I'll now be aware of when using these classes in the future.

Using Factory Methods to Simulate Map Literals in Java

Unlike many modern programming languages, Java does not support the notion of a "map literal"; that is, a map whose contents are declared using a dedicated language construct rather than being instantiated and populated via explicit API calls. For example, in Swift it is possible to create a dictionary (the Swift equivalent of a Java map) using the following syntax:

var dictionary = ["a": 1, "b": 2, "c": 3]

The result of executing this code is identical to the following, more verbose, version, which first allocates the dictionary and then populates it:

var dictionary = [String: Int]()

dictionary["a"] = 1
dictionary["b"] = 2
dictionary["c"] = 3

Similarly, an object can be constructed in JavaScript using the following literal syntax:

var object = {"a": 1, "b": 2, "c": 3};

or this more verbose equivalent:

var object = new Object();

object["a"] = 1;
object["b"] = 2;
object["c"] = 3;

Because Java does not support map literals, map instances must always be explicitly instantiated and populated. This is especially cumbersome if the map only needs to exist in the context of a single method call:

HashMap map = new HashMap();

map.put("a", 1);
map.put("b", 2);
map.put("c", 3);


Fortunately, it is possible to approximate the behavior of map literals in Java using factory methods. For example:

// Create a map from a variable length array of map entries
public static <K> Map<K, ?> mapOf(Map.Entry<K, ?>... entries) {
    HashMap<K, Object> map = new HashMap<>();

    for (Map.Entry<K, ?> entry : entries) {
        map.put(entry.getKey(), entry.getValue());

    return Collections.unmodifiableMap(map);

// Create a map entry
public static <K> Map.Entry<K, ?> entry(K key, Object value) {
    return new AbstractMap.SimpleImmutableEntry<>(key, value);

Using these methods, the previous example can be reduced to a single line of code:

process(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));

It may not be quite as elegant as the Swift or JavaScript versions, but it is a lot more convenient than creating and populating the map an element at a time.