Die Idee ist, für algebraische Datentypen (Optional, Either, List, Tuple…) Pattern Matching ähnlich wie in Scala als DSL anzubieten:
private static void testEither(Either<Integer, String> either) {
String s = match(either,
Left(42, () -> "die Antwort!"),
LeftIf(a -> a + " ist gerade", a -> a % 2 == 0),
Left(a -> "Links!"),
Right("foo", () -> "FOO"),
RightIf(a -> a + " ist lang", a -> a.length() > 10),
Default(x -> "nix gefunden: " + x.toString())
);
System.out.println(s);
}
Dabei sind in gewissem Umfang auch geschachtelte Strukturen möglich:
private static void testOptEither(Optional<Either<Integer,String>> opt) {
String s = match(opt,
None(() -> "leer"),
Some(Left(12, () -> "12 links!")),
Some(RightIf(x -> x, x -> x.length() == 3)),
Default(x -> "nix gefunden: " + x.toString())
);
System.out.println(s);
}
Der gewählte Ansatz ist recht einfach strukturiert (im Gegensatz zu allgemeineren Versionen wie http://kerflyn.wordpress.com/2012/05/09/towards-pattern-matching-in-java/ ), aber meiner Meinung nach trotzdem recht nützlich, und vor allem auch clientseitig recht leicht auf “eigene” Klassen erweiterbar. Die einzelnen “Fälle” müssen dazu nur ein recht einfaches Interface implementieren:
import java.util.Optional;
public interface Case<T,R> {
Optional<R> accept(T value);
}
Eine Implementierung sieht dann z.B. so aus:
public static <A, B, R> Case<Either<A, B>, R> LeftIf(Function<A, R> fn, Predicate<A> predicate) {
return t -> t.isLeft() && predicate.test(t.getLeft())
? of(fn.apply(t.getLeft()))
: Optional.<R>empty();
}
Die von mir gewählte Großschreibung ist eine bewußte Abweichung von Java-Standard:
[ul]
[li] Ähnlichkeit zu Scalas Pattern-Matching
[/li][li] Ähnlichkeit zu einem “Konstruktor” (also sozusagen ein “Destruktor”)
[/li][li] Beugt Name-Clashes mit anden Methoden (wie Either.left()
) oder Schlüsselwörtern (Default
) vor
[/li][/ul]
Bei solchen DSLs ist natürlich die Typinferenz immer recht diffizil (meine IDE meint auch öfters, dass bestimmte Konstrukte falsch wären, während es Java 8 problemlos schluckt). Insbesondere besteht potentiell die Gefahr, dass Konstrukte akzeptiert werden, die eigentlich nicht matchen sollten, was natürlich entsprechend getestet werden sollte.
Gibt es Meinungen dazu?