Java 8是否支持Scala和其他功能程序的模式匹配呢?我正在一起介绍Java 8的Lambda功能。我在这个特定的功能编程概念中找不到任何东西。
我记得让我对函数式编程感兴趣的是quicksort实现,特别是与命令式编程的实现相比。
答案 0 :(得分:30)
我认为你不是在谈论在字符串上应用正则表达式的模式匹配,而是applied in Haskell。例如,使用通配符:
head (x:_) = x
tail (_:xs) = xs
Java 8将不支持本机,但Lambda表达式有这样的方法,比如计算阶乘:
public static int fact(int n) {
return ((Integer) new PatternMatching(
inCaseOf(0, _ -> 1),
otherwise( _ -> n * fact(n - 1))
).matchFor(n));
}
如何实现您可以在此博文中找到更多信息:Towards Pattern Matching in Java。
答案 1 :(得分:9)
可以在Java 8中实现模式匹配作为库(利用lambda表达式),但不幸的是,我们仍然会遗漏编译器穷举检查Haskell或Scala等语言。
Cyclops-react有一个强大的Pattern Matching模块,它为Java 8提供结构模式匹配,并通过警卫提供模式匹配。
它提供了一个when / then /其他DSL和匹配,包括解构基于标准的Java Predicates(因此匹配可以用来过滤Stream)。
对于匹配防护装置,我们使用whenGuard / then / otherwise来清楚地显示案件正在驱动测试而不是被测对象的结构。
e.g。对于基于防护的匹配,如果我们实现了一个实现Matchable接口的Case类
static class MyCase implements Matchable{ int a; int b; int c;}
(顺便说一下,Lombok可以非常方便地创建密封的案例类层次结构)
我们可以匹配它的内部值(必要时递归,或者通过各种其他选项中的类型)。
import static com.aol.cyclops.control.Matchable.otherwise;
import static com.aol.cyclops.control.Matchable.whenGuard;
new MyCase(1,2,3).matches(c->c.is(whenGuard(1,2,3)).then("hello"),
.is(whenGuard(4,5,6)).then("goodbye")
,otherwise("goodbye")
);
如果我们有一个没有实现[Matchable] [3]的对象,我们可以将它强制转换为Matchable,我们的代码将成为
Matchable.ofDecomposable(()->new MyCase(1,2,3)))
.matches(c->c.is(whenGuard(1,2,3)).then("hello"),
.is(whenGuard(4,5,6)).then("goodbye")
,otherwise("hello"));
如果我们不关心其中一个值,我们可以使用通配符
new MyCase(1,2,3).matches(c->c.is(whenGuard(1,__,3)).then("hello"),
.is(whenGuard(4,__,6)).then("goodbye")
,otherwise("hello)
);
或者递归地解构一组嵌套的类
Matchable.of(new NestedCase(1,2,new NestedCase(3,4,null)))
.matches(c->c.is(whenGuard(1,__,has(3,4,__)).then("2")
,otherwise("default");
NestedCase看起来像这样 -
class NestedCase implemends Decomposable { int a; int b; NestedCase c; }
用户还可以使用hamcrest
组合模式匹配表达式 import static com.aol.cyclops.control.Matchable.otherwise;
import static com.aol.cyclops.control.Matchable.then;
import static com.aol.cyclops.control.Matchable.when;
Matchable.of(Arrays.asList(1,2,3))
.matches(c->c.is(when(equalTo(1),any(Integer.class),equalTo(4)))
.then("2"),otherwise("default"));
我们还可以匹配被测试对象的确切结构。那不是使用if / then测试结果是否恰好匹配我们的情况,我们可以让编译器确保我们的情况与提供的对象的结构相匹配。执行此操作的DSL与基于防护的匹配几乎完全相同,但我们使用when / then / otherwise来清楚地显示对象结构驱动测试用例而不是反之亦然。
import static com.aol.cyclops.control.Matchable.otherwise;
import static com.aol.cyclops.control.Matchable.then;
import static com.aol.cyclops.control.Matchable.when;
String result = new Customer("test",new Address(10,"hello","my city"))
.match()
.on$_2()
.matches(c->c.is(when(decons(when(10,"hello","my city"))),then("hello")), otherwise("miss")).get();
//"hello"
从客户提取的地址对象的结构匹配。 Customer和Address类看起来这个
@AllArgsConstructor
static class Address{
int house;
String street;
String city;
public MTuple3<Integer,String,String> match(){
return Matchable.from(()->house,()->street,()->city);
}
}
@AllArgsConstructor
static class Customer{
String name;
Address address;
public MTuple2<String,MTuple3<Integer,String,String>> match(){
return Matchable.from(()->name,()->Maybe.ofNullable(address).map(a->a.match()).orElseGet(()->null));
}
}
cyclops-react提供了一个Matchables类,它允许对常见的JDK类型进行结构模式匹配。
答案 2 :(得分:2)
我知道这个问题已经得到了回答,而且我对函数式编程很陌生,但是在经过多次犹豫之后,我终于决定在这次讨论中受到关注,以获得有关后续内容的反馈。
我建议下面的(太?)简单实现。它与接受的答案中引用的(好)文章略有不同;但在我的(短期)体验中,它使用起来更灵活,易于维护(当然这也是一种品味问题)。
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
final class Test
{
public static final Function<Integer, Integer> fact = new Match<Integer>()
.caseOf( i -> i == 0, i -> 1 )
.otherwise( i -> i * Test.fact.apply(i - 1) );
public static final Function<Object, String> dummy = new Match<Object>()
.caseOf( i -> i.equals(42), i -> "forty-two" )
.caseOf( i -> i instanceof Integer, i -> "Integer : " + i.toString() )
.caseOf( i -> i.equals("world"), i -> "Hello " + i.toString() )
.otherwise( i -> "got this : " + i.toString() );
public static void main(String[] args)
{
System.out.println("factorial : " + fact.apply(6));
System.out.println("dummy : " + dummy.apply(42));
System.out.println("dummy : " + dummy.apply(6));
System.out.println("dummy : " + dummy.apply("world"));
System.out.println("dummy : " + dummy.apply("does not match"));
}
}
final class Match<T>
{
public <U> CaseOf<U> caseOf(Predicate<T> cond, Function<T, U> map)
{
return this.new CaseOf<U>(cond, map, Optional.empty());
}
class CaseOf<U> implements Function<T, Optional<U>>
{
private Predicate<T> cond;
private Function<T, U> map;
private Optional<CaseOf<U>> previous;
CaseOf(Predicate<T> cond, Function<T, U> map, Optional<CaseOf<U>> previous)
{
this.cond = cond;
this.map = map;
this.previous = previous;
}
@Override
public Optional<U> apply(T value)
{
Optional<U> r = previous.flatMap( p -> p.apply(value) );
return r.isPresent() || !cond.test(value) ? r
: Optional.of( this.map.apply(value) );
}
public CaseOf<U> caseOf(Predicate<T> cond, Function<T, U> map)
{
return new CaseOf<U>(cond, map, Optional.of(this));
}
public Function<T,U> otherwise(Function<T, U> map)
{
return value -> this.apply(value)
.orElseGet( () -> map.apply(value) );
}
}
}
答案 3 :(得分:0)
http://ricostacruz.com/nprogress是一个库,旨在支持对java的和类型和结构模式匹配的近原生支持(甚至更多)。 以小型计算器DSL为例,使用Derive4J,您可以编写以下代码:
import java.util.function.Function;
import org.derive4j.Data;
import static org.derive4j.exemple.Expressions.*;
@Data
public abstract class Expression {
interface Cases<R> {
R Const(Integer value);
R Add(Expression left, Expression right);
R Mult(Expression left, Expression right);
R Neg(Expression expr);
}
public abstract <R> R match(Cases<R> cases);
private static Function<Expression, Integer> eval = Expressions
.match()
.Const(value -> value)
.Add((left, right) -> eval(left) + eval(right))
.Mult((left, right) -> eval(left) * eval(right))
.Neg(expr -> -eval(expr));
public static Integer eval(Expression expression) {
return eval.apply(expression);
}
public static void main(String[] args) {
Expression expr = Add(Const(1), Mult(Const(2), Mult(Const(3), Const(3))));
System.out.println(eval(expr)); // (1+(2*(3*3))) = 19
}
}
答案 4 :(得分:0)
这是一篇有关Java 8中结构化模式处理的有趣文章。它建议最后实现一个简单的实现。
http://blog.higher-order.com/blog/2009/08/21/structural-pattern-matching-in-java/
答案 5 :(得分:0)
JMPL是一个简单的Java库,可以使用Java 8功能来模拟某些功能模式匹配。
matches(data).as(
new Person("man"), () -> System.out.println("man");
new Person("woman"), () -> System.out.println("woman");
new Person("child"), () -> System.out.println("child");
Null.class, () -> System.out.println("Null value "),
Else.class, () -> System.out.println("Default value: " + data)
);
matches(data).as(
Integer.class, i -> { System.out.println(i * i); },
Byte.class, b -> { System.out.println(b * b); },
Long.class, l -> { System.out.println(l * l); },
String.class, s -> { System.out.println(s * s); },
Null.class, () -> { System.out.println("Null value "); },
Else.class, () -> { System.out.println("Default value: " + data); }
);
matches(figure).as(
Rectangle.class, (int w, int h) -> System.out.println("square: " + (w * h)),
Circle.class, (int r) -> System.out.println("square: " + (2 * Math.PI * r)),
Else.class, () -> System.out.println("Default square: " + 0)
);