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 支持多种正则表达式解析方式进行匹配,具体如下:
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)
}
位于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中被认为是设计失败的检查型异常。
捕获异常
使用 Either 处理异常
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 的基础就到这里了,希望对大家有所帮助!