Scala拓展
Scala拓展
一、Scala模式匹配
1、match表达式
- 类似Java switch语句
- 能处理任何类型
- 不需要break
- 能够生成值
//基本模式匹配
def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
matchTest(3) // many
matchTest(1) // one
//模式守卫(在模式后面加上if 条件)
def matchTest2(x: Int): String = x match {
case i if i==1 => "one"
case i if i>2 => "大于2"
case _ => "many"
}
matchTest2(3) // 大于2
matchTest2(1) // one
//仅匹配类型
def matchTest3(x: Any): String = x match {
case x:Int => "Int"
case x:String => "String"
case _ => "Any"
}
matchTest3(3.0) // Any
matchTest3(1) // Int
2、样例类的模式匹配
- 模式匹配
- 检查某个值(value)是否匹配某一个模式的机制,一个成功的匹配同时会将匹配值解构为其组成部分
//样例类的模式匹配
def matchTest4(x: Student)= x match {
case Student(name,19) => println(name)
case Student("Tom",age) => println(age)
case Student(name,age) => println(name,age)
case _ => println("no matches")
}
matchTest4(Student("Jason",19))
matchTest4(Student("Tom",20))
matchTest4(Student("Jimmy",20))
3、非样例类的模式匹配
- 单例对象中指定unapply()方法时,称为提取器对象(Extractor Objects)
- unapply()方法接受一个实例对象,返回最初创建它所用的参数
object MatchDemo extends App {
def matchTest05(x:Student)=x match {
case Student(name,age) if age <20 => println("young")
case Student(name,age) if age >30 => println("old")
case _=>println("else")
}
matchTest05(Student("zhangsan",18))
matchTest05(Student("lisi",25))
matchTest05(Student("wangwu",35))
}
//定义一个普通类
class Student(n:String,a:Int) {
//定义一下成员变量
var name=n
var age=a
}
object Student{
def apply(n: String, a: Int): Student = new Student(n, a)
def unapply(arg: Student): Option[(String, Int)] = {
//实现提取器的逻辑代码
if (arg==null) None else Some(arg.name,arg.age)
}
}
//输出结果
young
else
old
4、偏函数
- 偏函数是只对函数定义域的一个子集进行定义的函数
- PartialFunction[-A,+B]是一个特质
- A为函数定义域,B为偏函数返回值类型
- apply()
- isDefinedAt()
//自定义偏函数
val inc = new PartialFunction[Any, Int] {
def apply(any: Any) = any.asInstanceOf[Int]+1
def isDefinedAt(any: Any) =
if (any.isInstanceOf[Int]) true else false
}
List(1,2,3,"four").collect(inc)
- case语句
val pf:PartialFunction[Any, Int]={case x:Int=>x+1} //返回一个偏函数
List(1,2,3,"four").collect(pf) //输出List(2,3,4)
5、scala注解方法
- 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(){}
}
6、运算符
- 在Scala中,运算符即是方法。任何具有单个参数的方法都可以用作中缀运算符
10.+(1)
——>10+1
- 定义和使用运算符
- 算数运算符
- 关系运算符
- 逻辑运算符
- 赋值运算符
- 位运算符
case class Vec(val x: Double, val y: Double) {
def +(that: Vec) = new Vec(this.x + that.x, this.y + that.y)
def add(that: Vec) = new Vec(this.x + that.x, this.y + that.y)
}
val vector1 = Vec(1.0, 1.0)
val vector2 = Vec(2.0, 2.0)
val vector3 = vector1 + vector2 // 或者 vector1 add vector2
vector3.x // 3.0
vector3.y // 3.0
二、scala正则表达式
1、matches方法
- Scala支持多种正则表达式解析方式
- String.matches()方法
- 正则表达式模式匹配
- scala.util.matching.Regex API
//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
//使用“.r”方法可使任意字符串变成一个Regex实例
"L3R 6M2" match {
case ZipcodePattern(zc) => println("Valid zip-code: " + zc ) //zc为第1个分组结果,可以匹配多个分组
case zc => println("Invalid zip-code: " + zc )
}
2、scala.util.matching.Regex
- findFirstMatchIn() 返回第一个匹配(Option[Match])
- findAllMatchIn() 返回所有匹配结果(Regex.Match)
- findAllIn() 返回所有匹配结果(String)
import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]".r
numberPattern.findFirstMatchIn("awesomepassword") match {
case Some(_) => println("Password OK") //匹配成功
case None => println("Password must contain a number") //未匹配
}
3、捕获分组
识别“name:Jason,age:19,……”中的键值对
import scala.util.matching.Regex
val studentPattern:Regex="([0-9a-zA-Z-#() ]+):([0-9a-zA-Z-#() ]+)".r
val input="name:Jason,age:19,weight:100"
for(patternMatch<-studentPattern.findAllMatchIn(input)){
println(s"key: ${patternMatch.group(1)} value: ${patternMatch.group(2)}")
}
4、字符串替换
//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
5、在字符串中查找模式
val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-05-23" match {
case date(year, month, day) => println(year,month,day)
}
"2014-05-23" match {
case date(year, _*) => println("The year of the date is " + year)
}
"2014-05-23" match {
case date(_*) => println("It is a date")
}
6、实例测试
- 现有如下日志信息,请使用Scala正则表达式解析如下信息
- 日志级别
- 日期
- 请求URI
"INFO 2016-07-25 requestURL:awewaeqweqwe", "INFO 2016-07-25 requestURL:waewqeqwe", "INFO 2016-07-25 requestURL:qweqweqweqwfasdf"
import scala.io.Source
val filePath="D:\\study files\\Scala\\test\\1.txt"
val file: BufferedSource = Source.fromFile(filePath)
val regex = """(\w{4}) (\d{4}-\d{2}-\d{2}) [^:]*:(.*)""".r
for (s<- file.getLines()){
s match {
case regex(level,date,uri)=>println(s"日志级别:$level,日期:$date,uri:$uri")
case _=>println("无匹配")
}
}
三、隐式类
1、隐式转换
- 隐式参数、隐式函数
- 隐式转换函数是以implicit关键字声明的带有单个参数的函数
- 这种函数将会自动应用,将值从一种类型转换到另一种类型
- 隐式类:用implicit关键字修饰的类,其主构造器可用于隐式转换
- 只能在类、Trait、对象(单例对象、包对象)内部定义
- 构造器只能携带一个非隐式参数
- 隐式类不能是case class
- 在同一作用域内,不能有任何方法、成员或对象与隐式类同名
object ImplictDemo {
//定义一个隐式类
implicit class Stringinprove(val s:String){
def increment=s.map(x=>(x+1).toChar)
}
}
object TestDemo11{
def main(args: Array[String]): Unit = {
import ImplictDemo._
println("test".increment)
}
}
//输出结果
uftu
2、隐式类应用
- 为String对象增加新的方法
object Stringutils {
implicit class StringImprovement(val s:String){//隐式类
def increment=s.map(x=>(x +1).toChar)
}
}
object Main extends App{
import Stringutils._
println("mobin".increment) //输出:npcjo
}
四、异常
1、抛出异常
throw new 异常类型
2、捕获异常
try{
//todo
}catch{
case ex:异常类型=>{ //todo }
……
}finally{
//todo
}
try {
val f=new File("input.txt")
if(!f.canWrite)
throw new Exception("file can't write")
val file=Source.fromFile(f);
for(line<-file.getLines()) println(line)
} catch {
case ex: FileNotFoundException => {
println("Missing file exception")
}
case ex: IOException => {
println("IO Exception")
}
case ex: Exception => {
println(ex.getMessage)
}
} finally {
println("Exiting finally...")
}
3、使用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)
4、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)
5、failAsValue
- 发生异常时使用缺省值
scala.util.control.Exception.failAsValue(classOf[Exception])(-9999)("42a".toInt)
五、scala高级类型
1、结构类型
- 指一组关于抽象方法、字段和类型的规格说明
//定义结构类型
{
def sayHello(name:String):Unit
}
//结构类型作为函数参数
def f(a:{def sayHello():Unit}){a.sayHello}
//函数调用
f(new {def sayHello():Unit={println("hello")}})
2、复合类型
- 复合类型可以由多个对象类型构成,主要用于缩短已有对象成员的签名
- 格式为:A with B with C … { refinement }
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集成java API
- 需求
- 在Scala中使用Java API计算今天、昨天……等日期
- 分析
- java.text.SimpleDateFormat
- java.util.Calendar
- java.util.Date
object JavaApiDemo extends App {
//定义一个日期格式
val dateFmt="yyyy-MM-dd"
def today():String={
val sdf = new SimpleDateFormat(dateFmt)
val date = new Date
sdf.format(date)
}
println(today())
val calendar:Calendar = Calendar.getInstance()
val sdf = new SimpleDateFormat(dateFmt)
calendar.roll(Calendar.WEEK_OF_MONTH,1)
private val str:String = sdf.format(calendar.getTime())
println(str)
}