The important classes are Case, Matcher, MultiReturnTypeFunction, and Switch.
Case is a special type of Exception which does not fill in its stack trace when thrown (for performance reasons). MultiReturnTypeFunction throws a variety of Cases, which are caught by Switch and matched against the available Matchers until a match is found. The Match's apply method is called and the result is the Switch's result.
public abstract class Case extends Exception {
/**
* It's important to override this to reduce the time it takes to throw.
*/
@Override
public Case fillInStackTrace() {
return this;
}
}
public interface Matcher<U> {
public boolean matches(Case c);
public U apply(Case c);
}
public interface MultiReturnTypeFunction<T> {
/**
* Never returns normally, always throws a Case.
*/
public void apply(T param) throws Case;
}
public class Switch <T, U> {
public <T, U> U match (MultiReturnTypeFunction gen, T param, Matcher<U> defaultCase, Matcher<U>... matchers) {
try {
gen.apply(param); // always throws a Case
}
catch (Case e) {
for (Matcher<U> m : matchers)
if (m.matches(e))
return m.apply(e);
return defaultCase.apply(e);
}
throw new IllegalStateException("No matcher found for " + param + " in " + gen);
}
}
I have some example code to show this in use. It's simply finds the sign of a series of random Integers and prints them to standard output.
First we need Case corresponding to each case - Positive, Negative, and Zero. We could also have null, but I think that's overkill for this example.
class CaseNegative extends Case {}
class CasePositive extends Case {}
class CaseZero extends Case {}
And the example code:
public class Main {
public static void main(String[] args) {
MultiReturnTypeFunction<Integer> signOf = new MultiReturnTypeFunction<Integer>() {
public void apply(Integer param) throws Case {
if (param > 0) {
throw new CasePositive();
}
if (param == 0) {
throw new CaseZero();
}
throw new CaseNegative();
}
};
Matcher<String> throwExceptionMatcher = new Matcher<String>() {
public boolean matches(Case c) {
return true;
}
public String apply(Case c) {
throw new IllegalStateException("No matching matcher found for " + c);
}
};
Matcher<String> positiveValueMatcher = new Matcher<String>() {
public boolean matches(Case c) {
return c instanceof CasePositive;
}
public String apply(Case c) {
return "Positive";
}
};
Matcher<String> negativeValueMatcher = new Matcher<String>() {
public boolean matches(Case c) {
return c instanceof CaseNegative;
}
public String apply(Case c) {
return "Negative";
}
};
Matcher<String> zeroValueMatcher = new Matcher<String>() {
public boolean matches(Case c) {
return c instanceof CaseZero;
}
public String apply(Case c) {
return "Zero";
}
};
Switch<Integer, String> _switch = new Switch <Integer, String>();
for (int i = 0; i < 10; i++)
{
int val = new Random().nextInt(3) - 1;
String sign = _switch.match(signOf, val, throwExceptionMatcher,
zeroValueMatcher, negativeValueMatcher, positiveValueMatcher);
System.out.println(val + " is " + sign);
}
}
}