Mario has posted 14 posts at DZone. You can read more from them at their website. View Full User Profile

Java Switch on Steroids

04.12.2010
| 7772 views |
  • submit to reddit
The native Java switch construct has been often criticized for its limited applicability, since it can operate only on ints, chars and (starting from Java 5) enums. For example Scala has demonstrated how power and flexible its pattern matching construct could be. Getting inspiration from it, the last version of lambdaj introduces a Switcher object that through a smart use of its closures and the matchers provided by hamcrest, greatly enriches the features of the java switch. That allows to implement factory and strategy pattern in a readable and almost declarative way.

For example let's suppose you need a strategy that switchs among three sorting algorithms based on some characteristic of the list to be sorted. In particular let's assume we have an algorithm specialized for Strings:
public List<String> sortStrings(List<String> list) {
// a sort algorithm suitable for Strings
}
another one that works well with small lists having no more than 100 items:
public List<T> sortSmallList(List<T> list) {
// a sort algorithm suitable for no more than 100 items
}
and a more general purpose one:
public List<String> sort(List<String> list) {
// a generic sort algorithm
}
Given these 3 sorting methods it is possible to create a strategy that chooses the most suitable of them in the following declarative way:
Switcher<List<T>> sortStrategy = new Switcher<List<T>>()
.addCase(having(on(List.class).get(0), instanceOf(String.class))),
new Closure() {{ of(this).sortStrings(var(List.class)); }})
.addCase(having(on(List.class).size(), lessThan(100))),
new Closure() {{ of(this).sortSmallList(var(List.class)); }})
.setDefault(new Closure() {{ of(this).sort(var(List.class)); }});
In this way it is possible to sort a list using the best available algorithm by invoking the Switcher as it follows:
List<T> sortedList = sortStrategy.exec(list, list);
In this case, the list must be passed twice to the Switcher: once to decide, through the hamcrest Matchers, which sorting method should be used and once to be passed to the closure that will actually do the sort.

The release 2.2 of lambdaj also allows to define blocks that invoke constructors. By using this last feature, it is easy to define a Switcher implementing a factory pattern, that creates different objects based on different conditions once again defined through hamcrest matchers.
Published at DZone with permission of its author, Mario Fusco.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Ronald Miura replied on Mon, 2010/04/12 - 5:23am

What about

        if (list.get(0) instanceof String) {
            return sortStrings(list);
        } else if (list.size() < 100) {
            return sortSmallList(list);
        } else {
            return sort(list);
        }

?

Mario Fusco replied on Mon, 2010/04/12 - 6:47am in response to: Ronald Miura

Of course that works as well. Personally I don't like very long if ... else if ... else if ... chains. In this cases I prefer to use the switch statement, but, as I wrote, I found it very limitating. That's why I tried to extend its applicability.

Jeff Szeto replied on Mon, 2010/04/12 - 9:11am

It might just be your example... It seems to me that your usage of the switcher has much more ceremony (poor signal-to-noise ratio) than simply using if-else. Just counting how braces & parentheses you have used there, you got the idea. Of course, we understand the advantage of using switch instead of if-else. But I think this issue is better to be solved from language perspective (I think it's part of Java 7) and that's where the true benefit comes - keep the code clean and easy to read/maintain.

Mario Fusco replied on Mon, 2010/04/12 - 9:31am in response to: Jeff Szeto

You are right about the poor signal-to-noise ratio, but this is the best I could do with the current Java syntax and features.

For what I know Java 7 will just add the possibility to switch on Strings. If that is true, my Switcher will be still more powerfull than that. Indeed if you pass as first parameter to its addCase() method any kind of object instead of an Hamcrest matcher it automatically converts it in an equalTo() matcher with the given object as argument. It means that you can switch on object on any class by using the object's equals() method and not only on Strings.

Liam Knox replied on Tue, 2010/04/13 - 5:35pm in response to: Mario Fusco

Are you kidding?

Compared to your example you can actually see what it is doing very, very easily. And that is by far the most important point. If functional/closure syntax digress from this fact, dont use them.

Kirk Pepperdine replied on Tue, 2010/04/13 - 10:25pm

Sorry, but this is a load of mung!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.