scala 高级扩展详解(模式匹配和正则表达式)

scala 系列

scala 入门基础

scala 数组集合

scala 143个数组函数大全

scala 函数

scala OOP

scala 高级扩展



前言

上一篇博客已经给大家介绍了 scala OOP, 掌握了OOP 的知识后,就已经算是进入 scala 的门了。scala OOP基础是 spark 和 flink 的基础。

本篇博客将为大家带来 scala 高级扩展的介绍。主要包括模式匹配和正则表达式,此外还有异常处理、注解和高级类型的简单了解。


思维导图

在这里插入图片描述

模式匹配

scala中有一个非常强大的模式匹配机制,类似Java switch语句,但其能处理类型所有类型,不需要break,并且能够生成值,这是 Java switch 不具备的。

scala 模式匹配可以分为简单模式匹配、匹配类型、守卫、匹配样例类、匹配集合、变量声明和正则匹配。

简单模式匹配

在 Java 中,有 switch 关键字,可以简化if条件判断语句。在scala中,可以使用match表达式替代。

语法:

val match {
	case value1 => expression 表达式1
	case value2 => expression 表达式2
	...
	case _ => expression 表达式n			// 默认匹配		相当于java switch 的 default
}

例如:

// 出入一个Int整数,如果是1,就加10;如果是2,就加20,;其他就加30
def abc(x:Int) = x match {
  case 1 => x+10
  case 2 => x+20
  case _ => x+30
}

类似Java switch语句,case 后面跟常量,进行判断匹配。

匹配类型

除了像Java中的switch匹配数据之外,match表达式还可以进行类型匹配。如果我们要根据不同的数据类型,来执行不同的逻辑,也可以使用match表达式来实现。

语法:

val match {
	case value1:type1 => expression 表达式1
	case value2:type2 => expression 表达式2
	...
	case _ => expression 表达式n			// 默认匹配		相当于java switch 的 default
}

例如:

// 对传入的类型进行不同的操作
def bbb(x:Any) = x match {
  case x:Int  => x.asInstanceOf[Int]+10
  case x:String  => s"hello $x"
  case _ => x
}

如果case表达式中无需使用到匹配到的变量,可以使用下划线代代替。

守卫

scala 为了简化 java case 多个匹配值带来的代码冗余,scala 在普通模式匹配后面加上if 条件,这也意味着模式守卫支持 表达式的匹配形式,是 java case 不能够支持的地方。

例如:

// 对输入的Int类型的参数进行分段不同的操作
def aaa(x:Int) = x match {
  case x if x<3 =>x+10
  case x if x<=5 =>x+20
  case _ => x+30
}

匹配样例类

scala可以使用模式匹配来匹配样例类,从而可以快速获取样例类中的成员数据。

case class Student(var name:String,var age:Int)

def ccc(x:Student) = x match {
  case Student("hubert", age) => println(s"hubert $age")
  case Student(name, 22) => println(s"$name 22")
  case Student(name, age) => println(name,age)
  case _ => println("no match")
}

事实上模式匹配不仅支持样例类的匹配,也支持如下非样例类的模式匹配:

class Student(_name:String,_age:Int) {
  var name=_name
  var age=_age
}
object Student{
  def apply(name: String, age: Int): Student = new Student(name, age)
  def unapply(arg: Student): Option[(String, Int)] ={
    if(arg==null) None else Some(arg.name,arg.age)  
  }
}

def matchTest(x:Student)=x match {
    case Student(name,age) if age<=20 => println("young man")
    case Student(name,age) if age>20 => println("old man")
}

matchTest(Student("Jason",19))   //young man

从上面可以看出 ,非样例类的模式匹配必须实现提取器 unapply 的方法。单例对象中指定unapply()方法时,称为提取器对象(Extractor Objects);unapply()方法接受一个实例对象,返回最初创建它所用的参数。

unapply是将该类的对象,拆解为一个个的元素的 Option 对象。使用 Option 类型,可以用来有效避免空引用(null)指针异常。也就是说,将来我们返回某些数据时,可以返回一个Option类型来代替。

Option

Option 中 使用Some(value) 表示实际的值,使用None 表示空引用(null)指针异常。而在实际开发中,通常通过使用getOrElse方法,当值为None是可以指定一个默认值。

例如:

object High {
  def div(a:Double,b:Double)={
    if (b!=0){
      Some(a/b)
    }else{
      None
    }
  }

  def main(args: Array[String]): Unit = {
    println(div(1, 0).getOrElse(0))   //输出0
  }
}

匹配集合

scala中的模式匹配,还能用来匹配集合。

def main(args: Array[String]): Unit = {
  // 数组匹配
  val arr = Array(1,2,3)
  arr match {
    case Array(1,x,y) => println("1 x y(x,y不固定)")
    case Array(0) => println("only 0")
    case Array(0,_*) => println("0 ...")
    case _ => println("no match")
  }
  
  // 列表匹配
  val list = List(0,2,3)
  list match {
    case 0 :: Nil =>  println("only 0")
    case 0 :: tail => println("0 ...")
    case x :: y :: Nil => println("x y(x,y不固定)")
    case _ => println("no match")
  }
  
  // 匹配元组
  val tuple = (2,3,5)
  tuple match {
    case (1,x,y) => println("1 ...")
    case (x,y,5) => println("... 5")
    case _ => println("no match")
  }
}

变量声明

在定义变量的时候,可以使用模式匹配获取数据。

scala> val arr = (1 to 10).toArray
arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val Array(_,x,y,z,_*) = arr
x: Int = 2
y: Int = 3
z: Int = 4

scala> val list = (1 to 10).toList
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val x::y::tail = list
x: Int = 1
y: Int = 2
tail: List[Int] = List(3, 4, 5, 6, 7, 8, 9, 10)

正则匹配

def main(args: Array[String]): Unit = {
    var source = Source.fromFile("log/log.txt","UTF-8")
    val logs = source.getLines().toArray
    val regex = """(INFO|ERROR) ([0-9]{4}-[0-9]{2}-[0-9]{2}) requestURL:(.*)""".r
    
    logs.filter(_.matches("""(INFO|ERROR) ([0-9]{4}-[0-9]{2}-[0-9]{2}) requestURL:(.*)""")).foreach(x=>x match {
      case regex(level,logdate,url) => println(level,logdate,url)
    })
  }

正则匹配实际上使用的是结构匹配。类似元组匹配。

正则表达式

在 scala 中,可以很方便地使用正则表达式来匹配数据。scala 中正则主要是通过 Regex 类来实现的具体如下:

  • scala 中提供了 Regex 类来定义正则表达式
  • 要构造一个 RegEx 对象,直接使用String类的r方法即可
  • 建议使用三个双引号来表示正则表达式,不然就得对正则中的反斜杠来进行转义

匹配

Scala 支持多种正则表达式解析方式进行匹配,具体如下:

  • String.matches()方法
  • 正则表达式模式匹配
  • scala.util.matching.Regex API
def main(args: Array[String]): Unit = {
  //String.matches
  "!123".matches("[a-zA-Z0-9]{4}")  //false
  "34Az".matches("[a-zA-Z0-9]{4}")  //true

  //模式匹配,Regex实现了提取器
  val ZipcodePattern = """([a-zA-Z][0-9][a-zA-Z] [0-9][a-zA-Z][0-9])""".r
  "L3R 6M2" match {
    case ZipcodePattern(zc) => println("Valid zip-code: " + zc )  //zc为第1个分组结果,可以匹配多个分组
    case zc => println("Invalid zip-code: " + zc )
  }
}

上述使用“.r”方法可使任意字符串变成一个Regex实例matches方法经常用在正则切割、替换、查找处理的前提工作,相当于过滤器 filter。

分割

scala 中正则分割多数用来解析数据,拿出有用的信息,最常用的就是正则中的分组。

下面是解析{"id":"123456","frields":{"name":"zs","age":"40"}}这条json对象的信息的id、name、age的值:

object RegexTest {
  def main(args: Array[String]): Unit = {
    //{"id":"123456","frields":{"name":"zs","age":"40"}}   
    val a = """{"id":"123456","frields":{"name":"zs","age":"40"}}"""
    val regex = "\\{\"id\":\"(.*?)\",\"frields\":\\{\"name\":\"(.*?)\"\\,\"age\":\"(.*?)\"\\}\\}".r
    regex.findAllMatchIn(a).foreach(x=>println(x.group(1),x.group(2),x.group(3))
    // 输出(123456,zs,40)

	// 单独取出 name 的值
	a match {
      case regex(_,name,_) => println(name)
      case _ => println("no match")
    }
  }
}

替换

scala 中正则分割多数用来解析数据,拿出有用的信息,通常也会用到正则替换,这样方便我们去正则切割去取有用的信息,注意源数据是不能修改的。

例如:

object High01 {
  def main(args: Array[String]): Unit = {
    //search
    val nums = "[0-9]+".r.findAllIn("123 Main Street Suite 2012")
    nums.next   // -> 123
    nums.next  // -> 2012

    //replace
    "[0-9]+".r.replaceFirstIn("234 Main Street Suite 2034", "567") //234->567
    "[0-9]+".r.replaceAllIn("234 Main Street Suite 2034", "567") //234、2034->567
  }
}

查找

scala 中利用 scala.util.matching.Regex 有三种正则查找方式:

  • findFirstMatchIn() 返回第一个匹配(Option[Match])
  • findAllMatchIn()返回所有匹配结果(Regex.Match)
  • findAllIn() 返回所有匹配结果(String)

例如:

def main(args: Array[String]): Unit = {
  val reg = "[0-9]".r
  reg.findFirstMatchIn("ab2cd") match {
    case Some(x) => println(x)
    case None => println("no")
  }

  // findAllIn返回值:scala.util.matching.Regex.MatchIterator
  println(reg.findAllIn("ab2cd2 4 d").toList)   // List(2, 2, 4)

  // findAllMatchIn返回值:scala.Iterator[scala.util.matching.Regex.Match   
  println(reg.findAllMatchIn("ab2cd2 4 d").toList)		// List(2, 2, 4)
}

注解(Annotation)

  • 位于Scala标准库注解包——scala.annotation

  • 注解语法:@注解名称(注解参数...)

  • 常用注解:@throws、@deprecated、@unchecked、@SerialVersionUID……

  • 可使用注解的地方:类、方法、方法参数、字段、局部变量

例如:

object DeprecationDemo extends App{
  @deprecated("deprecation message", "release # which deprecates method")
  def hello = "hola"
  @throws(classOf[Exception])
  def test(){}  
}

异常处理

在 scala 中的异常处理和 java 异常处理是一样的。

抛出异常

我们可以在一个方法中,抛出异常。语法格式和Java类似,使用 throw new Exception...

scala不需要在方法上声明要抛出的异常,它已经解决了再Java中被认为是设计失败的检查型异常。

捕获异常

和 java 一样,scala 捕获异常语法如下:
在这里插入图片描述

  • try中的代码是我们编写的业务处理代码
  • 在catch中表示当出现某个异常时,需要执行的代码
  • 在finally中,是不管是否出现异常都会执行的代码

使用 Either 处理异常

  • Either[A, B] 表示要么包含一个类型为A的实例,要么包括一个类型为B的实例
  • Either只有两个子类型:Left、Right,如果Either[A, B]对象包含的是A的实例,则它是Left实例,否则是Right实例
  • Either用于异常处理时,一般约定:Left 代表出错的情况,Right 代表成功的情况
def divide(x:Int): Either[String,Int] ={
  if(x==0)
    Left("除数不能为0")
  else
    Right(100/x)
}
def test(x:Int)=divide(x) match {
    case Left(errMsg)=>println(errMsg)
    case Right(result)=>println(result)
}
test(0)
test(1)

allCatch

scala.util.control.Exception.allCatch.opt("42".toInt)      // Some(42)
scala.util.control.Exception.allCatch.opt("42a".toInt)    // None

scala.util.control.Exception.allCatch.toTry("42".toInt)  // 42
scala.util.control.Exception.allCatch.toTry("42a".toInt)  // Failure (e)

scala.util.control.Exception.allCatch.withTry("42".toInt)  // Success(42)
scala.util.control.Exception.allCatch.withTry("42a".toInt)  // Failure (e)

scala.util.control.Exception.allCatch.either("42".toInt)  // Right(42)
scala.util.control.Exception.allCatch.either("42a".toInt)  // Left(e)

failAsValue 发生异常时使用缺省值

scala.util.control.Exception.failAsValue(classOf[Exception])(-9999)("42a".toInt)

高级类型

结构类型

指一组关于抽象方法、字段和类型的规格说明。

//定义结构类型
{
    def sayHello(name:String):Unit
}
//结构类型作为函数参数
def f(a:{def sayHello():Unit}){a.sayHello}
//函数调用
f(new {def sayHello():Unit={println("hello")}})

复合类型

复合类型可以由多个对象类型构成,主要用于缩短已有对象成员的签名:

trait X1 
trait X2
//定义复合类型参数x
def test(x: X1 with X2) = {println("ok")}
//函数调用,实参为匿名对象
test(new X1 with X2)
object A extends X1 with X2
//实参为单例对象
test(A)

到此,关于 scala 的基础就到这里了,希望对大家有所帮助!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值