使用scala模式匹配而不是java switch case有什么好处?

时间:2014-01-25 19:17:07

标签: java scala functional-programming pattern-matching

每个人都说模式匹配是函数式语言的一个很好的特性。为什么呢?

我不能简单地使用ifs和切换案例吗?

我想了解使用模式匹配而不是常规过程编程ifs和switch case的优点

5 个答案:

答案 0 :(得分:22)

我首先要注意的是,你没有使用“代替”switch语句的模式匹配。 Scala没有switch语句,它所具有的是匹配块,其中的表面看起来非常类似于switch语句。

使用模式匹配匹配块执行switch所做的所有事情,以及更多。

A)它不仅限于Oracle在语言规范中选择“祝福”的原语和其他类型(字符串和枚举)。如果你想匹配你自己的类型,请继续前进!

B)模式匹配也可以提取。例如,使用元组:

val tup = ("hello world", 42)
tup match {
  case (s,i) =>
    println("the string was " + s)
    println("the number was " + i
}

列表:

val xs = List(1,2,3,4,5,6)
xs match {
  case h :: t =>
    // h is the head: 1
    // t is the tail: 2,3,4,5,6
    // The :: above is also an example of matching with an INFIX TYPE
}

使用案例类

case class Person(name: String, age: Int)
val p = Person("John Doe", 42)
p match {
  case Person(name, 42) =>
    //only extracting the name here, the match would fail if the age wasn't 42
    println(name)
}

C)模式匹配可以用于值赋值和for-comprehensions ,而不仅仅是在匹配块中:

val tup = (19,73)

val (a,b) = tup

for((a,b) <- Some(tup)) yield a+b // Some(92)

D)匹配块是表达式,而不是语句

这意味着他们会根据匹配的情况评估身体,而不是完全通过副作用来表现。这对函数式编程至关重要!

val result = tup match { case (a,b) => a + b }

答案 1 :(得分:6)

不知怎的,我对@KevinWright回答的编辑/添加被抛弃了,所以我将它添加到这里作为一个更好的模式匹配功能......

F)编译器详尽检查案例。

如果存在与现有案例不涵盖的值匹配,编译器将向您发出警告。这是该语言的一个非常好的功能,因为如果您不忽略这些编译器警告,您将不会捕获此类运行时异常或遇到您没有想到的情况。如果仍然运行应用程序并忽略警告,如果您的值与任何情况都不匹配,您将获得一个很好的描述性异常。这是一个例子:

scala> def badMatch(l: List[Int]): Unit = l match { case x :: xs => println(x) }
<console>:7: warning: match may not be exhaustive.
It would fail on the following input: Nil
       def badMatch(l: List[Int]): Unit = l match { case x :: xs => println(x) }
                                          ^
badMatch: (l: List[Int])Unit

scala> badMatch(List(1, 2))
1

scala> badMatch(Nil)
scala.MatchError: List() (of class scala.collection.immutable.Nil$)

我更喜欢在这种情况下获得异常,因为它会大声而清晰地失败,通常是早期而不是执行意外的逻辑分支。

如果您使用if,则必须使用else,如果使用Java switch,您必须拥有default个案才能涵盖所有案例。但请注意区别:在这种情况下,Scala编译器知道您的空列表与非空列表不同,或者更广泛地说,您定义匹配的粒度。您可以将列表与1或2个元素匹配并忽略其余元素,或使用任何其他更复杂的模式,而不必担心是否设法覆盖所有情况。

简而言之,当您使用复杂的提取和匹配逻辑时,编译器将确保您不会错过任何情况。除非您使用defaultelse等默认案例,否则Java中没有类似内容。

答案 2 :(得分:3)

模式匹配不是 switch语句的替代品,我认为这是在oop中执行动态调度的另一种方式。他们尝试做同样的事情:根据参数的动态类型调用函数的不同版本

答案 3 :(得分:2)

正如其他答案中所写的那样,Scala模式匹配和Java开关并没有做同样的事情。

切换声明:

  • 仅适用于本机类型,枚举类型和String类
  • 根据命令式编程,它可以替代“if-else”链来创建多个执行路径

模式匹配:

  • 允许使用第一个匹配政策匹配任何类型的数据
  • 它符合一个功能逻辑:每个case语句返回一个值,整个match语句实际上是一个返回匹配case值的函数。

换句话说,您可以将“模式匹配”用于“java开关”的类似目的,但这样做就是以命令的方式使用功能工具。

答案 4 :(得分: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)
       );