Skip to content

Instantly share code, notes, and snippets.

@johnlcox
Last active August 29, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnlcox/d6dded9807c5f6580626 to your computer and use it in GitHub Desktop.
Save johnlcox/d6dded9807c5f6580626 to your computer and use it in GitHub Desktop.
Java 8 Pattern Matching
import static GuavaOptionalPattern.caseNone;
import static GuavaOptionalPattern.caseSome;
import static IntegerPattern.caseOf;
import static OrRelsePattern.orElse;
import static PatternMatching.match;
import com.google.common.base.Optional;
public class Examples {
public String matchInteger(int x) {
return match(x).on(
caseOf(1, x -> "one"),
caseOf(2, x -> "two"),
orElse(_ -> "many")
);
}
public String matchOptionalString(Optional<String> opt) {
return match(opt).on(
caseSome(str -> str),
caseNone(() -> "No String")
);
}
public void runExamples() {
System.out.println(matchInteger(3));
System.out.println(matchOptionalString(Optional.of("Hello World"))
}
}
// TODO: Needs work. Do the generics actually work out? Is it possible to get a class cast exception with this?
public class GuavaOptionalPattern<T> implements Pattern<T> {
public static <S, T> Pattern<T> caseSome(Function<S, T> function) {
return new GuavaOptionalPresentPattern<S, T>(function);
}
public static <S, T> Pattern<T> caseNone(Supplier<T> supplier) {
return new GuavaOptionalAbsentPattern<S, T>(supplier);
}
private static class GuavaOptionalPresentPattern<S, T> implements Pattern<T> {
private final Function<S, T> function;
private GuavaOptionalPresentPattern(Function<S, T> function) {
this.function = function;
}
public boolean matches(Object value) {
return value.isInstanceOf(Optional.class) && ((Optional<S>) value).isPresent();
}
public T apply(Object value) {
return function.apply((T) ((Optional<S>) value).get());
}
}
private static class GuavaOptionalAbsentPattern<S, T> implements Pattern<T> {
private final Supplier<T> supplier;
public GuavaOptionalAbsentPattern(Supplier<T> supplier) {
this.supplier = supplier;
}
public boolean matches(Object value) {
return value.isInstanceOf(Optional.class) && !((Optional<S>) value).isPresent();
}
public T apply(Object value) {
return supplier.get();
}
}
}
public class IntegerPattern<T> implements Pattern<T> {
private final Integer value;
private final Function<Integer, T> function;
private IntegerPattern(Integer value, Function<Integer, T> function) {
this.value = value;
this.function = function;
}
public static <T> Pattern<T> caseOf(int value, Function<Integer, T> function) {
return new IntegerPattern<T>(value, function);
}
public static <T> Pattern<T> caseOf(Integer value, Function<Integer, T> function) {
return new IntegerPattern<T>(value, function);
}
public boolean matches(Object value) {
return value.equals(value);
}
public T apply(Object value) {
return function.apply((Integer) value);
}
}
public class ListPattern {
public static <S, T> Pattern<T> caseHeadTail(Function<S, List<S>, T> function) {
}
public static <S, T> Pattern<T> caseNil(Supplier<T> supplier) {
}
public static <S, T> Pattern<T> caseOf2(Function<S, S, T> function) {
}
public static <S, T> Pattern<T> caseOf3(Function<S, S, S, T> function) {
}
public static <S, T> Pattern<T> caseOf4(Function<S, S, S, S, T> function) {
}
}
public class MatchingException extends RuntimeException {
public MatchingException(String message) {
super(message);
}
}
public class OrElsePattern<T> implements Pattern<T> {
private final Function<Object, T> function;
private OrElsePattern(Function<Object, T> function) {
this.function = function;
}
public static <T> Pattern<T> orElse(Function<Object, T> function) {
return new OrElsePattern<T> function);
}
public boolean matches(Object value) {
return true;
}
public T apply(Object value) {
return function.apply(value);
}
}
public interface Pattern<T> {
public boolean matches(Object value);
public T apply(Object value);
}
public class PatternMatching {
private final Object value;
private PatternMatching(Object value) {
this.value = value;
}
public static PatternMatching match(Object value) {
return new PatternMatching(value);
}
public <T> on(Pattern<T>... patterns) {
for (Pattern<T> pattern : patterns) {
if (pattern.matches(value)) {
return pattern.apply(value);
}
}
throw new MatchException("no match for " + value);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment