Wednesday, September 4, 2013

A Monoflop class for easier looping...

Whether you want to join the contents of a collection or build a URL query string. There are lot's of cases where you have to handle to first iteraton of a loop a bit different from all others. Often I used this construct:

List<String> listToJoin = ...
boolean first = true;
StringBuilder result = new StringBuilder();
for(String item : listToJoin) {
   if (!first) {
      result.append(", ");
   }
   first = false;
   result.append(item);
}

System.out.println(result);
Yes, this works like a charm, but just looks plain ugly. And don't ask how long one has to debug if you get the position of the first = false wrong.

A simple class called Monoflop can help here. A properly commented version can be found on GitHub, but a very short version will do here:

public class Monoflop {

    private boolean toggled = false;
    /**
     * Reads and returns the internal state.

     * Toggles it to true once.
     */
    public boolean successiveCall() {
        if (toggled) {
            return true;
        }
        toggled = true;
        return false;
    }

    /**
     * Inverse of successiveCall

     */
 
    public
boolean firstCall() {
        return !successiveCall();
    }

}
Using this neat helper results in the following:
List<String> listToJoin = ...
Monoflop mf = new Monoflop();
StringBuilder result = new StringBuilder();
for(String item : listToJoin) {
   if (mf.successiveCall()) {
      result.append(", ");
   }
   result.append(item);
}

System.out.println(result);
Granted, you didn't save a whole lot of line in this example. However the logic is much more visible and you have less possibilities for errors. The only thing which is a bit misleading is that a call named successiveCall() has side-effects. On the otherhad, as it toggles the internal state, I didn't want to make it a getter (isSuccessiveCall()) since that would be even more evil.

Feel free to use this class in your own code base (but use the one from GitHub - as it is better documented). However, if you like it and you have uses for the fastest dependency injection framework out there, with lots of other features, check out: http://sirius-lib.net (GitHub). SIRIUS (which contains Monoflop) is OpenSource (MIT license) and developed and maintained by scireum GmbH.