Java developers have 99 problems…

… but this ain’t one.

Today Yahuda Katz posted his 10 favourite things about the ruby language. His list certainly reflects most of the things I find very appealing about the language. The sixth item highlights Ruby’s excellent support for blocks and lambdas and an argument is mounted that when performing file operations in languages without them, programmers are forced to use an inline “ensure” block every in the same lexical scope that they originally opened the file in, to ensure that the resource is closed. As is often the case the comparison is made to Java, but as any seasoned Java developer will tell you (and this point has probably be made many, many times) it just isn’t true. Java supports a safer and comparable idiom via the anonymous inner class.

The example given is a very succinct Ruby method to print out the lines of a text file. Ruby’s File.open ensures the file is properly closed after the block has completed, normally or otherwise:

def run(input)
  File.open(input, "r") do |f|
    f.each_line {|line| puts line }
  end
endCode language: Ruby (ruby)

The Java version listed does the same but, predictably, is far more verbose and laborious:

static void run(String in) 
throws FileNotFoundException {
  File input = new File(in);
  String line; Scanner reader = null;
  try {
    reader = new Scanner(input);
    while(reader.hasNextLine()) {
      System.out.println(reader.nextLine());
    }
  } finally { reader.close(); }
}Code language: JavaScript (javascript)

However no Java developer that values their sanity is ever going to sprinkle this pattern through their code base any time they want to use a File and ensure that it is closed properly. Here’s what they are going to use instead:

public interface Processor {
  void process(T target);
}Code language: PHP (php)
import java.io.*;
import java.util.Scanner;

public class FileSlurper {
 
  public static void slurp(String fileName, Processor processor) 
    throws FileNotFoundException {

    File input = new File(fileName);
    Scanner reader = null;
    try {
      reader = new Scanner(input);
      processor.process(reader);
    }
    finally {
      reader.close();
    }
  }

}Code language: JavaScript (javascript)

Once that infrastructure is in place, the Java implementation of the example becomes:

FileSlurper.slurp(input, new Processor() {
  public void process(Scanner reader) {
    while(reader.hasNextLine())
      System.out.println(reader.nextLine());
  }
});Code language: JavaScript (javascript)

No one can argue that this is as pretty or convenient as the Ruby version, but it does ensure that file opening and closing is handled correctly without any effort from the client code. The code in the anonymous inner class can even access variables in the current lexical context, as with the Ruby block, with the caveat that they must be declared final (not quite a lexical closure!). This pattern, in conjunction with the Processor interface may be used any time there is a need for similar resource acquisition and clean–up procedures, as might be the case for locks or database connections.

Lambdas and blocks are very useful constructs, and the anonymous inner class can act as an acceptable, if far from ideal, analogue. What an anonymous inner class can’t do is act as a co–routine; this is a truly powerful feature of Ruby’s blocks and associated method invocation features that Java can’t directly compete with.

One thing’s for certain: the Ruby community won’t win over Java developers by giving examples of deficiencies where none exist.


Posted

in

by

Tags:

Comments

2 responses to “Java developers have 99 problems…”

  1. steve Avatar
    steve

    Nice article – just wanted to ask if there was a name for the Java pattern you explained. Thanks

  2. Christopher Owen Avatar

    Hi Steve,

    The pattern in both Ruby and Java is an example of the Command pattern. Ruby’s implementation is closest to that of a Functor, but many people would also loosen the definition of Functor to include the Java example, given that Java does not support function pointers.

    SO: What is the difference between a functor and the command pattern
    Apache Commons Functor

Leave a Reply

Your email address will not be published. Required fields are marked *