元组
映射是K/V对偶的集合,对偶是元组的最简单形式,元组可以装着多个不同类型的值。
创建元组
获取元组中的值
元组中下标默认从1开始
将对偶的集合转换成映射
拉链操作
zip命令可以将多个值绑定在一起
转换为映射关系显示
注意:如果两个数组的元素个数不一致,拉链操作后生成的数组的长度为较小的那个数组的元素个数
集合
Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质
在Scala中集合有可变(mutable)和不可变(immutable)两种类型,immutable类型的集合初始化后就不能改变了(注意与val修饰的变量进行区别)
序列Seq
不可变的序列 import scala.collection.immutable._
在Scala中列表要么为空(Nil表示空列表)要么是一个head元素加上一个tail列表。
9 :: List(5, 2) :: 操作符是将给定的头和尾创建一个新的列表
注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))
list常用的操作符:
+: (elem: A): List[A] 在列表的头部添加一个元素
:: (x: A): List[A] 在列表的头部添加一个元素
:+ (elem: A): List[A] 在列表的尾部添加一个元素
++[B](that: GenTraversableOnce[B]): List[B] 从列表的尾部添加 另外一个列表
::: (prefix: List[A]): List[A] 在列表的头部添加另外一个列表
object ImmutListDemo {
def main(args: Array[String]) {
//创建一个不可变的集合
val lst1 = List(1,2,3)
//将0插入到lst1的前面生成一个新的List
val lst2 = 0 :: lst1
//类似于调用::方法
val lst3 = lst1.::(0)
val lst4 = 0 +: lst1
val lst5 = lst1.+:(0)
//将一个元素添加到lst1的后面产生一个新的集合
val lst6 = lst1 :+ 4
val lst0 = List(4,5,6)
//将2个list合并成一个新的List
val lst7 = lst1 ++ lst0
//将lst1插入到lst0前面生成一个新的集合
val lst8 = lst1 ++: lst0
//将lst0插入到lst1前面生成一个新的集合
val lst9 = lst1.:::(lst0)
println(lst9)
}
}
1.创建一个不可变的集合
2.将0插入到lst1的前面生成一个新的List
//将0插入到lst1的前面生成一个新的List
val lst2 = 0 :: lst1
//类似于调用::方法 val lst3 = lst1.::(0)
val lst4 = 0 +: lst1
val lst5 = lst1.+:(0)
//将一个元素添加到lst1的后面产生一个新的集合 val lst6 = lst1 :+ 3
可变的序列 import scala.collection.mutable._
import scala.collection.mutable.ListBuffer
object MutListDemo extends App{
//构建一个可变列表,初始有3个元素1,2,3
val lst0 = ListBuffer[Int](1,2,3)
//创建一个空的可变列表
val lst1 = new ListBuffer[Int]
//向lst1中追加元素,注意:没有生成新的集合
lst1 += 4
lst1.append(5)
//将lst1中的元素最近到lst0中, 注意:没有生成新的集合
lst0 ++= lst1
//将lst0和lst1合并成一个新的ListBuffer 注意:生成了一个集合
val lst2= lst0 ++ lst1
//将元素追加到lst0的后面生成一个新的集合
val lst3 = lst0 :+ 5
}
1.创建一个可变列表
2.向lst1中追加元素,注意:没有生成新的集合
lst1
+=
append
3.将lst1中的元素添加至lst0中 注意没有生成新的集合
4.将lst0和lst1合并成一个新的ListBuffer 注意:生成了一个集合
5.将元素追加到lst0的后面生成一个新的集合
Set
不可变的Set
object ImmutSetDemo extends App{
val set1 = new HashSet[Int]()
//将元素和set1合并生成一个新的set,原有set不变
val set2 = set1 + 4
//set中元素不能重复
val set3 = set1 ++ Set(5, 6, 7)
val set0 = Set(1,3,4) ++ set1
println(set0.getClass)
}
元素与set1合并生成一个新的set(set2),原有set(set1)不变
set中元素不能重复
两个集合合并产生新的集合----> ++操作
可变的Set
object MutSetDemo extends App{
//创建一个可变的HashSet
val set1 = new mutable.HashSet[Int]()
//向HashSet中添加元素
set1 += 2
//add等价于+=
set1.add(4)
set1 ++= Set(1,3,5)
println(set1)
//删除一个元素
set1 -= 5
set1.remove(2)
println(set1)
}
1.创建一个可变的HashSet
2.向HashSet中添加元素 +=操作等价于.add
3.向一个集合中加入另一个集合 ++=操作 (Set中不能重复)
4.删除一个元素
-=等价于remove
Map
object MutMapDemo extends App{
val map1 = new mutable.HashMap[String, Int]()
//向map中添加数据
map1("spark") = 1
map1 += (("hadoop", 2))
map1.put("storm", 3)
println(map1)
//从map中移除元素
map1 -= "spark"
map1.remove("hadoop")
println(map1)
}
1.向Map中添加数据(三种方式皆可)
2.从Map中移除元素
-= 与 remove作用相同
类、对象、继承、特质
Scala的类与Java、C++的类比起来更简洁,学完之后你会更爱Scala!!!
类
类的定义
//在Scala中,类并不用声明为public。
//Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
class Person {
//用val修饰的变量是只读属性,有getter但没有setter
//(相当与Java中用final修饰的变量)
val name= "zhangsan"
//用var修饰的变量既有getter又有setter (get和set方法)
var age: Int = 18
//类私有字段,在本类中使用(伴生对象中也可使用)
private var id :String ="123456"
//对象私有字段,访问权限更加严格的,Person类的方法只能访问到当前对象的字段
//(只能在Person类中使用)
private[this] val sex = "M"
private[this] var addr :String=_
}
//这是包的访问权限,这个类在com包及其子包中可见
private [com] class Person {
}
//单例对象
object Student{
def main(args: Array[String]): Unit = {
var M = new Man("zhsnafan",12)
print(M.id)
}
}
构造器
注意:主构造器会执行类定义中的所有语句
/**
*每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起
*/
class Student(val name: String, val age: Int){
//主构造器会执行类定义中的所有语句
println("执行主构造器")
try {
println("读取文件")
throw new IOException("io exception")
} catch {
case e: NullPointerException => println("打印异常Exception : " + e)
case e: IOException => println("打印异常Exception : " + e)
} finally {
println("执行finally部分")
}
private var gender = "male"
//用this关键字定义辅助构造器
//定义多个辅助构造器,当参数数量、参数类型一致时,构造器的参数类型的顺序不能一致
def this(name: String, age: Int, gender: String){
//每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
this(name, age)
println("执行辅助构造器")
this.gender = gender
}
//辅助构造器2
def this(name:String,Course:String,age:Int){
this(name,age)
}
}
/**
*构造器参数可以不带val或var,如果不带val或var的参数至少被一个方法所使用,
*那么它将会被提升为字段
*/
//在类名后面加private就变成了私有的
class Queen private(val name: String, prop: Array[String], private var age: Int = 18){
println(prop.size)
//prop被下面的方法使用后,prop就变成了不可变得对象私有字段,等同于private[this] val prop
//如果没有被方法使用该参数将不被保存为字段,仅仅是一个可以被主构造器中的代码访问的普通参数
def description = name + " is " + age + " years old with " + prop.toBuffer
}
object Queen{
def main(args: Array[String]) {
//私有的构造器,只有在其伴生对象中使用
val q = new Queen("hatano", Array("蜡烛", "皮鞭"), 20)
println(q.description())
}
}
对象
单例对象
在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的
-
存放工具方法和常量
-
高效共享单个不可变的实例
-
单例模式
object SingletonDemo {
def main(args: Array[String]) {
//单例对象,不需要new,用【类名.方法】调用对象中的方法
val session = SessionFactory.getSession()
println(session)
}
}
object SessionFactory{
//该部分相当于java中的静态块
var counts = 5
val sessions = new ArrayBuffer[Session]()
while(counts > 0){
sessions += new Session
counts -= 1
}
//在object中的方法相当于java中的静态方法
def getSession(): Session ={
sessions.remove(0)
}
}
class Session{
}
伴生对象
在Scala的类中,与类名相同的对象叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性
class Dog {
val id = 1
private var name = "zhiyou"
//伴生对象无法访问此对象
private[this] val sex:String="M"
def printName(): Unit ={
//在Dog类中可以访问伴生对象Dog的私有属性
println(Dog.CONSTANT + name )
}
}
/**
* 伴生对象
*/
object Dog {
//伴生对象中的私有属性
private val CONSTANT = "汪汪汪 : "
def main(args: Array[String]) {
val p = new Dog
//访问私有的字段name
p.name = "123"
p.printName()
}
}
apply方法
通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用
//示例1
object ApplyDemo {
def main(args: Array[String]) {
//调用了Array伴生对象的apply方法
//def apply(x: Int, xs: Int*): Array[Int]
//arr1中只有一个元素5
val arr1 = Array(5)
println(arr1.toBuffer)
//new了一个长度为5的array,数组里面包含5个null
var arr2 = new Array(5)
}
}
//示例2
package com.zhiyoulxj.Scala
class Teacher {
var name:String = _
var id = 123
}
object Teacher{
def apply: Teacher = new Teacher(){
print(1)
}
def main(args: Array[String]): Unit = {
var t = Teacher
t.apply
// 使用new方法创建对象与调用apply方法作用相同
// var t1 =new Teacher
}
}
应用程序对象
Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。
object AppObjectDemo extends App{
//不用写main方法
println("I love you Scala")
}
继承
扩展类
在Scala中扩展类的方式和Java一样都是使用extends关键字
重写方法
在Scala中重写一个非抽象的方法必须使用override修饰符
类型检查和转换
Scala | Java |
obj.isInstanceOf[C] | obj instanceof C |
obj.asInstanceOf[C] | (C)obj |
classOf[C] | C.class |
超类的构造
object ClazzDemo {
def main(args: Array[String]) {
//val h = new Human
//println(h.fight)
}
}
//接口
trait Flyable{
def fly(): Unit ={
println("I can fly")
}
def fight(): String
}
//抽象类
abstract class Animal {
def run(): Int
val name: String
def eat(): Unit ={
print("吃饭")
}
}
class Human extends Animal with Flyable{
val name = "abc"
//打印几次"ABC"?
val t1,t2,(a, b, c) = {
println("ABC")
(1,2,3)
}
println(a)
println(t1._1)
------接口
//接口中的方法无论是否实现,子类调用都需要加上override
override def fight(): String = {
"fight with 棒子"
}
override def fly(): Unit = {
// super.fly()
print("我爱自由")
}
------超类
//在子类中重写超类的抽象方法(该抽象方法在超类中没有实现)时,
//不需要使用override关键字,写了也可以
def run(): Int = {
1
}
//超类或接口中实现过的方法在子类中调用都需要加上override(重写)
override def eat(): Unit = {
// super.eat()
print("吃满汉全席")
}
}
多实现
如果想多继承,先用extends继承一个抽象类,然后再用with关键字实现一个接口,extends既可以继承抽象类,也可以实现接口,如果想要多重实现,则继续 with 接口名
模式匹配和样例类
Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句、类型检查等。
并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配
匹配字符串
Match case
object CaseDemo01 extends App{
val arr = Array("YoshizawaAkiho", "YuiHatano", "AoiSola")
val name = arr(Random.nextInt(arr.length))
name match {
case "YoshizawaAkiho" => println("吉泽老师...")
case "YuiHatano" => println("波多老师...")
case _ => println("真不知道你们在说什么...")
}
}
-----------------------------------------------------
object MatchDemo1 extends App {
val arr = Array("鲁班","张飞","李世民","太上道祖")
val name = arr(Random.nextInt(arr.length))
print(name)
name match {
case "鲁班" => print("小短腿儿")
case "张飞" => print("阉人")
case "李世民" => print("唐太宗")
case _ => print("太上斩情")
}
匹配类型
Int String Double
package cn.zhiyou.cases
import scala.util.Random
object CaseDemo01 extends App{
//val v = if(x >= 5) 1 else if(x < 2) 2.0 else "hello"
val arr = Array("hello", 1, 2.0, CaseDemo)
val v = arr(Random.nextInt(4))
println(v)
v match {
case x: Int => println("Int " + x)
case y: Double if(y >= 0) => println("Double "+ y)
case z: String => println("String " + z)
case _ => throw new Exception("not match exception")
}
}
注意:case y: Double if(y >= 0) => ...
模式匹配的时候还可以添加守卫条件。如不符合守卫条件,将掉入case _中
匹配数组、元组
object CaseDemo03 extends App{
val arr = Array(1, 3, 5)
arr match {
case Array(1, x, y) => println(x + " " + y)
case Array(0) => println("only 0")
case Array(0, _*) => println("0 ...")
case _ => println("something else")
}
val lst = List(3, -1)
lst match {
case 0 :: Nil => println("only 0") //只有0一个元素
case x :: y :: Nil => println(s"x: $x y: $y") //有两个元素
case 0 :: tail => println("0 ...") //有三个及三个以上的元素(0开头)
case _ => println("something else")
}
val tup = (2, 3, 7)
tup match {
case (1, x, y) => println(s"1, $x , $y")
case (_, z, 5) => println(z)
case _ => println("else")
}
}
注意:在Scala中列表要么为空(Nil表示空列表)要么是一个head元素加上一个tail列表。
9 :: List(5, 2) :: 操作符是将给定的头和尾创建一个新的列表
注意::: 操作符是右结合的,如9 :: 5 :: 2 :: Nil相当于 9 :: (5 :: (2 :: Nil))
样例类
在Scala中样例类是一种特殊的类,可用于模式匹配。case class是多例的,后面要跟构造参数,
case object是单例的
case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask
object CaseDemo04 extends App{
val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
arr(Random.nextInt(arr.length)) match {
case SubmitTask(id, name) => {
println(s"$id, $name")//前面需要加上s, $id直接取id的值
}
case HeartBeat(time) => {
println(time)
}
case CheckTimeOutTask => {
println("check")
}
}
}
Option类型
在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值9
object OptionDemo {
def main(args: Array[String]) {
val map = Map("a" -> 1, "b" -> 2)
val v = map.get("b") match {
case Some(i) => i
case None => 0
}
println(v)
//更好的方式
val v1 = map.getOrElse("c", 0)
println(v1)
}
}
map.getOrElse()主要就是防范措施,如果有值,那就可以得到这个值,如果没有就会得到一个默认值,传入的参数是(key,default)这种形式,返回值是:如果有key那就get(key),如果没有,就返回default
偏函数
被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配
object PartialFuncDemo {
def func1: PartialFunction[String, Int] = {
case "one" => 1
case "two" => 2
case _ => -1
}
def func2(num: String) : Int = num match {
case "one" => 1
case "two" => 2
case _ => -1
}
def main(args: Array[String]) {
println(func1("one"))
println(func2("one"))
}
}