Scala笔记(三)模式匹配、异常处理与泛型

一、模式匹配

Scala 中有一个非常强大的模式匹配机制,可以应用在很多场景:

  • switch 语句
  • 类型查询
  • 使用模式匹配快速获取数据

简单模式匹配

// 语法:match表达式
// 变量 match {
	// case "常量1" => 表达式1
	// case "常量2" => 表达式2
	// case "常量3" => 表达式3
	// case _ => 表达式4  // 默认匹配
// }

// 使用:
// 1. 从控制台读取输入单词
val input = StdIn.readLine()

// 2. 使用模式匹配判断单词是否能够匹配,如果匹配输出一句话
val result = input match {
  case "hadoop" => "大数据分布式存储和计算框架"
  case "zookeeper" => "大数据分布式协调服务框架"
  case "spark" => "大数据分布式内存计算框架"
  case _ => "未匹配"
}
println(result)

匹配类型

// 语法1:
// 变量 match {
	// case 类型1变量名:类型1 => 表达式1
	// case 类型2变量名:类型2 => 表达式2
	// case 类型3变量名:类型3 => 表达式3
	...
	// case _ => 表达式4
// }

// 使用2:不使用匹配到的变量,仅判断类型
// 变量 match {
	// case _:类型1 => 表达式1
	// case _:类型2 => 表达式2
	// case _:类型3 => 表达式3
	...
	// case _ => 表达式4
// }

// 使用:
// 1. 定义Any类型的变量
// val a:Any = "hadoop"
// val a:Any = 1
// val a:Any = 1.0
val a:Any = null

// 2. 使用模式匹配匹配数据类型
a match {
	case x:String => println(s"${x}是字符串类型")
	case x:Int => println(s"${x}是整型")
	case x:Double => println(s"${x}是双精度浮点型")
	case _ => println("未匹配")
}
  • 如果case表达式中无需使用到匹配到的变量,可以使用下划线代替

守卫

// 1. 从控制台读取一个数字
val input = StdIn.readInt()

// 2. 使用模式匹配匹配指定范围的数据,打印输出
input match {
	case x if x >= 0 && x <= 3 => println("[0-3]")
	case x if x >= 4 && x <= 8 => println("[4-8]")
	case _ => println("未匹配")
}

匹配样例类

// 1. 创建两个样例类
case class Person(name:String, age:Int)
case class Order(id:String)

def main(args: Array[String]): Unit = {
	// 2. 创建样例类对象,并赋值为Any类型
	val zhangsan:Any = Person("张三", 20)
	val order1:Any = Order("001")

	// 3. 进行模式匹配
	zhangsan match {
		case Person(name, age) => println(s"姓名:${name} 年龄:${age}")
		case Order(id) => println(s"ID为:${id}")
		case _ => println("未匹配")
	}
}

提取器

并不是所有的类都可以进行普通的模式匹配,样例类之所以可以直接进行模式匹配,是因为它自动实现了 apply(用类名来快速构建一个对象)、unapply(将该类的对象拆解为一个个的元素) 方法。普通的类要支持模式匹配,必须要实现一个提取器

// 语法:
// 在伴生对象中创建unapply方法
// def unapply(stu:Student:Option[(类型1, 类型2, 类型3...)]) = {
	// if(stu != null) {
		// Some((变量1, 变量2, 变量3...))
	// } else {
		// None
	// }
// }

// 使用:
// 1. 定义一个普通的类
class Student(var name:String, var age:Int)

// 2. 实现unapply方法来定义提取器
object Student{
	def unapply(student: Student): Option[(String, Int)] = {
		if(student != null) {
			// 返回一个Some封装数据
			Some((student.name, student.age))
		} else {
			None
		}
	}
}

// 3. 创建对象,使用模式匹配来提取值
def main(args: Array[String]): Unit = {
	val zhangsan = new Student("张三", 20)

	zhangsan match {
		case Student(name, age) => println(s"${name}, ${age}")
	}
}

匹配集合

匹配数组

// 1. 定义三个数组,用于匹配
val array1 = Array(1, 2, 3)
val array2 = Array(0)
val array3 = Array(0, 1, 2, 3, 4, 5)

// 2. 进行模式匹配
array3 match {
	case Array(1, x, y) => println(s"匹配三个元素的数组,第一个元素为1, ${x}, ${y}")
	case Array(0) => println("匹配一个元素的数组,元素值为0")
	case Array(0,_*) => println("第一个元素为0,数量不固定的数组")
}

匹配列表

// 1. 创建三个不同的List
val list1 = List(0)
val list2 = List(0, 1, 1, 2, 3, 3)
val list3 = List(10, 11)

// 2. 进行模式匹配
list1 match {
	case 0 :: Nil => println("只有一个元素且元素为0的列表")
	case 0 :: tail => println("第一个元素为0且数量不固定的列表")
	case x :: y :: Nil => println(s"列表只有两个元素:${x}, ${y}")
}

匹配元组

// 1. 创建两个元组用于模式匹配
val tuple1 = (1, 3, 4)
val tuple2 = (3, 4, 5)

// 2. 进行匹配
tuple1 match {
	case (1, x, y) => println("匹配三个元素且第一个元素为1的元组")
	case (x, y, 5) => println("匹配三个元素且最后一个元素为5的元组")
}

变量声明中的模式匹配

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

获取数组中的元素

// 1. 生成数组0-10
val array = (0 to 10).toArray

// 2.模式匹配获取第二个、三个、四个
val Array(_, x, y, z, _*) = array
println(x, y, z)  // (1,2,3)

获取List中的元素

// 1. 生成0-10列表
val list = (0 to 10).toList

// 2.在定义声明变量的时候,使用模式匹配,来匹配第一个、第二个元素
var x :: y :: tail = list
println(x, y)  // (0,1)

正则表达式

  • Regex 类
    • Scala 中提供了 Regex 类来定义正则表达式
    • 要构造一个 Regex 对象,直接使用 String 类的 r 方法即可
    • 建议使用三个双引号来表示正则表达式,不然就得对正则中的反斜杠来进行转义
  • findAllMatchIn 方法
    • 使用 findAllMatchIn 方法可以获取所有正则匹配到的字符串
// 使用1:定义一个正则表达式,来匹配邮箱是否合法
// 1. 定义一个Regex正则表达式对象
val regex = """.+@.+\..+""".r

// 2. 使用正则表达式对象匹配数据
val email1 = "qq12344@163.com"
val email2 = "qq12344@.com"

// 匹配第一个邮箱
if(regex.findAllMatchIn(email1).size == 0) {
	println(email1 + "是一个非法的邮箱")
} else {
	println(email1 + "是一个合法的邮箱")
}

// 使用2:找出列表中所有不合法的邮箱
// 1. 定义正则表达式对象
val regex = """.+@.+\..+""".r

// 2. 定义一个邮箱列表
val emailList = List("38112345@qq.com", "12345efwf@gmail.com", "zhangsan@163.com", "123wefaec.com")

// 3. 过滤出来不合法的邮箱列表
val invalidEmailList = emailList.filter {
	// 过滤出来没有找到匹配的字符串
	case email if regex.findAllMatchIn(email).size == 0 => true
	case _ => false
}

println(invalidEmailList)  // List(123wefaec.com)

// 使用3:实现将邮箱列表转换为邮箱运营商名称列表
// 1. 定义一个用于匹配邮箱的正则表达式(使用正则中的括号来进行分组)
val regex = """.+@(.+)\..+""".r

// 2. 定义一个邮箱列表
val emailList = List("38112345@qq.com", "12345efwf@gmail.com", "zhangsan@163.com", "123wefaec.com")

// 3. 使用集合的函数式操作来进行转换
val companyList = emailList.map {
	case email@regex(company) => s"${email} -> ${company}"
	case email => s"${email} -> 未知"
}
println(companyList)  // List(38112345@qq.com -> qq, 12345efwf@gmail.com -> gmail, zhangsan@163.com -> 163, 123wefaec.com -> 未知)

二、异常处理

捕获异常

// 语法:
// try {
	// 代码
// } catch {
	// case ex:异常类型1 => // 代码
	// case ex:异常类型1 => // 代码
// } finally {
	// 代码
// }

// 使用:
try{
	val a = 10 / 0
} catch {
	case _: ArithmeticException => println("The divisor cannot be 0")
	case ex: Exception => ex.printStackTrace()  // 更通用的异常应该排在更具体的异常之后
}
println("程序继续执行")

抛出异常

// scala不需要在方法上声明要抛出的异常
def main(args: Array[String]): Unit = {
	// 抛出一个异常
	throw new Exception("这是一个异常")
}

三、泛型

泛型方法

// 语法:
// def 方法名[泛型名词](...) = {
	// ...
// }

// 使用:
// 1. 定义一个方法获取数组中间的元素
def getMiddleEle[T](array: Array[T]) = array(array.length/2)

// 2. 调用该方法
def main(args: Array[String]): Unit = {
	println(getMiddleEle(Array(1, 2, 3, 4, 5)))  // 3
	println(getMiddleEle(Array("a", "b", "c", "d", "e")))  // c
	println(getMiddleEle(Array(1.0, 2.0, 3.0, 4.0, 5.0)))  // 3.0
}

泛型类

// 语法:
// class 类[T](val 变量名: T)

// 使用:
// 1. 创建泛型类,包含两个字段
class Pair[T](var a:T, var b:T)

// 2. 创建该泛型类的对象(定义不同类型的对象)
def main(args: Array[String]): Unit = {
	val pair1: Pair[String] = new Pair("hadoop", "spark")
	val pair2: Pair[Int] = new Pair(1, 2)
	val pair3: Pair[Double] = new Pair(1.0, 2.0)
	
	println(pair1.a, pair1.b)  // (hadoop,spark)
	println(pair2.a, pair2.b)  // (1,2)
	println(pair3.a, pair3.b)  // (1.0,2.0)
}

上下界

上界

// 语法:
// 表示泛型参数必须要从该类(或本身)继承
// [T <: 类型]

// 使用:
// 1. 创建一个类和它的子类
class Person
class Student extends Person

// 2. 创建一个泛型方法,并且给泛型方法指定一个上届
def demo[T <: Person](array: Array[T]) = println(array)

// 3. 使用不同的类型来调用泛型方法
def main(args: Array[String]): Unit = {
	demo(Array(new Person))
	demo(Array(new Student))
	
	// 编译报错: String类型不是Person类型或者是它的子类
	// demo(Array("hadoop"))
}

下界

// 语法:
// 表示泛型参数必须是某个类的父类(或本身)
// [T >: 类型]

// 使用:
// 1. 定义类和子类
class Person
class Policeman extends Person
class Superman extends Policeman

// 2. 定义泛型方法:指定泛型的类型上下界
def demo[T >: Policeman <: Person](array: Array[T]) = println(array)

// 3. 调用demo方法,传入不同类型的数组进行测试
def main(args: Array[String]): Unit = {
	demo(Array(new Person))
	demo(Array(new Policeman))
	// 编译报错:Superman并不是Policeman的父类
	// demo(Array(new Superman))
}

如果类既有上界、又有下界。下界写在前面,上界写在后面

协变、逆变、非变

在这里插入图片描述

非变

语法:class Pair[T]{}

  • Scala 和 Java 一样 默认泛型类是非变的
  • 类型 B 是 A 的子类型,Pair[A] 和 Pair[B] 没有任何从属关系。

协变

语法:class Pair[+T]

  • 类型 B 是 A 的子类型,Pair[B] 可以认为是 Pair[A] 的子类型
  • 参数化类型的方向和类型的方向是一致的

逆变

语法:class Pair[-T]

  • 类型 B 是 A 的子类型,Pair[A] 反过来可以认为是 Pair[B] 的子类型
  • 参数化类型的方向和类型的方向是相反的
// 使用:
// 1. 创建一个测试类和子类
class Super
class Sub extends Super

// 2. 分别创建使用协变、逆变、非变的泛型类
// 非变(默认)
class Temp1[T]
// 协变
class Temp2[+T]
// 逆变
class Temp3[-T]

// 3. 测试协变、逆变、非变(类型转换)
def main(args: Array[String]): Unit = {
	val temp1: Temp1[Sub] = new Temp1[Sub]
	// 非变不允许任何的转换
	// val temp2: Temp1[Super] = temp1
	
	// 协变
	val temp3: Temp2[Sub] = new Temp2[Sub]
	val temp4: Temp2[Super] = temp3
	
	// 逆变
	val temp5: Temp3[Super] = new Temp3[Super]
	val temp6: Temp3[Sub] = temp5
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值