Concise Java

While I do love Java, I have never liked the Java culture of writing verbose, new-happy, Design Patterns-addled code. It’s painful to read, hard to use, slow, and despite all the design patterning, often surprisingly un-general and un-composable.

First, let’s look at the unnecessary verbosity. Found in the Mitro codebase:

public final class RPC {
  public static class LoginToken {
    public String email;
    public long timestampMs;
    public String nonce;
    public boolean twoFactorAuthVerified=false;
    public String extensionId;
    public String deviceId;
  }
}

But this works just as well:

public final class RPC { 
  static class LoginToken {
    String email;
    long timestampMs;
    String nonce;
    boolean twoFactorAuthVerified;
    String extensionId;
    String deviceId;
  }
}

The default scope is package scope for a reason! It’s actually usually what you want. And all variables are born with well-defined initial values — no need to initialize primitives with 0 or reference types with null.

Consider a more complex example, also from Mitro: java/server/src/co/mitro/core/util/Random.java, a class to generate securely random alphanumeric strings.

public class Random {
  private static int fillCharRange(char start, char endInclusive, char[] output, int index) {
    for (char c = start; c <= endInclusive; c++) {
      output[index] = c;
      index += 1;
    }
    return index;
  }

  protected static char[] makeAlphaNumChars() {
    char[] output = new char[26+26+10];
    int index = fillCharRange('a', 'z', output, 0);
    index = fillCharRange('A', 'Z', output, index);
    index = fillCharRange('0', '9', output, index);
    assert index == output.length;
    return output;
  }

  private static final char[] ALPHANUM = makeAlphaNumChars();

  // caches SecureRandom objects because they are expensive
  private static final ConcurrentLinkedQueue RNG_QUEUE =
      new ConcurrentLinkedQueue();

  /** Returns a secure random password with numChars alpha numeric characters. */
  public static String makeRandomAlphanumericString(int numChars) {
    SecureRandom rng = RNG_QUEUE.poll();
    if (rng == null) {
      // automatically seeded on first use
      rng = new SecureRandom();
    }

    StringBuilder output = new StringBuilder(numChars);
    while (output.length() != numChars) {
      // nextInt()'s algorithm is unbiased, so this will select an unbiased char from ALPHANUM
      int index = rng.nextInt(ALPHANUM.length);
      output.append(ALPHANUM[index]);
    }

    RNG_QUEUE.add(rng);
    return output.toString();
  }
}

With less code, we can write a more general, better-documented, and more performant class:

public class RandomString {
  static final char[] Alphanumerics = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".toCharArray();
  static final char[] Alphabetics = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
  static final char[] Numerics = "0123456789".toCharArray();
  static class Lazy {
    static final SecureRandom Random = new SecureRandom();
  }

  /**
   * @param characterSet The set from which to randomly select characters.
   * @param length The length of the array to create.
   *
   * @return A securely-random character array.
   */
  public static char[] generate(char[] characterSet, int length) {
    char[] output = new char[length];
    generate(output, characterSet);
    return output;
  }

  /**
   * @param output The array to fill with random characters.
   * @param characterSet The set from which to randomly select characters.
   */
  public static void generate(char[] output, char[] characterSet) {
    for (int i = 0; i < output.length; i++) {
      output[i] = characterSet[Lazy.Random.nextInt(characterSet.length)];
    }
  }
}

The new version allows the caller to specify their own character set, provides 3 handy built-in character sets with build-time optimizable construction, allows the caller to choose between callee-allocates and caller-allocates versions (reducing news), and no unnecessary scope specifiers. I replaced the single-item ConcurrentLinkedQueue with a lazy initializer as a lagniappe. :)

Like C and C++, Java doesn’t have to be awful. Like C and C++, it can even be kind of nice. Cultural factors dominate language-technical ones.

Update: Thanks to Bruce Leidl for pointing out that, in this tiny class whose few methods all touch the SecureRandom object, the lazy initialization pattern is unnecessary. The Java class loader loads all classes lazily, and until a caller actually calls RandomString.generate, the SecureRandom will not be new’d. (I always want to save a new if I can, since I come from C World.) Thus the lazy initializer pattern (itself relying on the fact that the class loader also loads inner classes lazily) is overkill here — indeed, it’s bloat. :) Better code:

static final SecureRandom Random = new SecureRandom();
// ...
public static void generate(char[] output, char[] characterSet) {
  for (int i = 0; i < output.length; i++) {
    output[i] = characterSet[Random.nextInt(characterSet.length)];
  }
}