A Useful Example in Java, Ruby, and Groovy

04 June 2008

We've been using Java and Ruby for work, and we've recently been asked to look more toward Groovy where we had been using Ruby, so I rewrote a useful little iconv script which we use to re-encode large volumes of data (which the GNU iconv doesn't seem to want to handle).

For illustration, here are the implementations I wrote:

Java (40 lines):

import java.io.*;

public class Iconv {
    public static void main(final String[] args) throws Exception {
        if (args.length < 2) {
            System.out.println(
                    "Usage: Iconv <in>:<encoding> <out>:<encoding>");
            return;
        }

        final String[] ins = args[0].split(":");
        final String[] outs = args[1].split(":");

        final String inFile = ins[0];
        final String inEnc = ins[1];
        final String outFile = outs[0];
        final String outEnc = outs[1];

        Writer writer = null;
        try {
            writer = new OutputStreamWriter(
                    new FileOutputStream(outFile), outEnc);
            Reader reader = null;
            try {
                reader = new InputStreamReader(
                        new FileInputStream(inFile), inEnc);
                Integer character = null;
                while ((character = reader.read()) >= 0) {
                    writer.write(character);
                }
            } finally {
                if (reader != null)
                    reader.close();
            }
        } finally {
            if (writer != null)
                writer.close();
        }
    }
}

Ruby (20 lines):

#!/usr/bin/env jruby

require 'iconv'
require 'fileutils'

if ARGV.size < 2 then
    puts "Usage: iconv.rb <from>:<enc> <to>:<enc>"
    exit
end

in_file, in_enc = ARGV[0].split(":")
out_file, out_enc = ARGV[1].split(":")

Iconv.open(out_enc, in_enc) do |conv|
    File.open(out_file, 'w') do |out|
        File.open(in_file, 'r').each_line do |line|
            out.write(conv.iconv(line))
        end
    end
end

Groovy (19 lines):

#!/usr/bin/env groovy

if (args.size() < 2) {
    println "Usage: iconv.groovy <from>:<enc> <to>:<enc>"
    return
}

final ins = args[0].split(":")
final outs = args[1].split(":")
final from = ins[0]
final fromEnc = ins[1]
final to = outs[0]
final toEnc = outs[1]

new FileOutputStream(to).withWriter(toEnc) { writer ->
    new FileInputStream(from).withReader(fromEnc) { reader ->
        writer << reader
    }
}

Using the Groovy 1.6 beta, I could have used the new left-side array assignment syntax to shorten the groovy version to 15 lines:

...
[from, fromEnc] = args[0].split(":")
...

I had initially set out to skip over Groovy and just learn Ruby, as I had viewed Groovy as a sort of compromise -- Ruby would be the real twist of the mind, but alas, my neural pathways seem a bit more rigid than I had hoped. I can think a little quicker in Groovy than Ruby and get a few things done. Groovy is also a bit more compatible with the work directives handed down from on high -- we want to be a Java shop.

Update (2008-06-04): I updated the code above to reflect some comments. To be complete, the Java code should null check the streams it's trying to close in the finally blocks.


Filed Under: Technology Java Computers Work Groovy