Scala学习资料

Scala Language

Scala语言

Scala是一门多范式的编程语言,能够以一种优雅的方式来解决现实问题,同时支持面向对象和面向函数的编程风格。虽然它是强静态类型的编程语言,但是它强大的类型推断能力,使其看起来就像是一个动态编程语言。Scala语言最终会被编译成java字节码文件,可以和JVM无缝集成,并且可以使用Scala调用Java的代码库。Scala编程语言除了自身的特性以外,目前比较流行的Spark计算框架也是使用Scala语言编写。Spark 和 Scala 能够紧密集成,例如,使用Scala语言操作大数据集合时,用户可以像是在操作本地数据集那样简单操作Spark上的分布式数据集-RDD(这个概念是Spark 批处理的核心术语),继而简化大数据集的处理难度,简化开发步骤。

特点

  • 面向对象编程语言 传递数据 | 数据建模
  • 面向函数式编程语言 专门为数据而生的语言 传递函数 | 数据分析计算
  • 强大的集合计算能力 (后续课程介绍)

因为现在主流大数据计算框架均对Scala编程支持比较友好,例如:Kafka.0.11.0_2.11.tar.gz、Spark使用Scala,导致使用Scala语言可以高效实现数据分析处理。

编程指南:https://docs.scala-lang.org/tour/tour-of-scala.html

环境安装

下载对应的Scala版本:https://www.scala-lang.org/download/2.11.12.html

Windows版本安装

  • 点击 scala-2.11.12.msi双击msi文件安装
  • 配置Scala的环境变量SCALA_HOME变量
SCALA_HOME=C:\Program Files (x86)\scala
PATH=C:\Program Files\Java\jdk1.8.0_161/bin;C:\Program Files (x86)\scala/bin;
  • 打开Window窗口
C:\Users\Administrator>scala
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.
scala>

CentOS安装

  • 下载 scala-2.11.12.rpm
  • 安装配置Scala
[root@CentOS ~]# rpm  -ivh scala-2.11.12.rpm
Preparing...                ########################################### [100%]
   1:scala                  ########################################### [100%]
[root@CentOS ~]# scala
Welcome to Scala 2.11.12 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_171).
Type in expressions for evaluation. Or try :help.
scala>

IDEA集成Scala开发环境

在File>Setting>Plugins点击 install pluginfromdisk选项,选择 scala-intellij-bin-2018.2.11.zip安装成功后,重启IDEA

Scala变量

Scala语言没有基本数据类型,这一点和Java语言不同,在Scala中一切皆对象,以下是Scala语言中的常见类型和类型间的继承关系:
在这里插入图片描述
Scala是一门纯粹的面向对象编程语言,该语言没有基本类型。所有值类型都是AnyVal的子类,所有对象类型都是AnyRef的子类。一般所有的AnyVal类型都有字面值,所有AnyRef类型的默认值都是Null

变量定义

Scala语言是一种可以做类型自动推断的强类型的编程语言。变量的类型可以通过编译器在编译时自动推断出最终类型,因此在Scala中声明一个变量,需要告知编译器该变量的值是常量还是变量,例如:声明一个变量使用var关键字,声明一个常量使用val关键字。Scala语言的变量声明语法如下:

[var|val] 变量名[:变量类型]=变量值[:类型]
scala> var i:Int=1:Int
i: Int = 1

scala> var i=1:Int
i: Int = 1

scala> var i=1
i: Int = 1

scala> var j=1
j: Int = 1

scala> var j=1:Byte
j: Byte = 1

scala> var j:Byte=1
j: Byte = 1

由于Scala语言具有强大的类型推断能力,因此在声明变量的时候,如果类型不存在歧义,一般可以省略

asInstanceOf

当类型兼容时,使用asInstanceOf[目标类型]强转,例如:Long转换Int、Double转换为Float,大->小 类型兼容

scala> var j:Byte=1
j: Byte = 1

scala> var i=10
i: Int = 10

scala> var j:Byte=0
j: Byte = 0

scala> j=i
<console>:13: error: type mismatch;
 found   : Int
 required: Byte

scala> i=j
i: Int = 0

scala> j=i.asInstanceOf[Byte]
j: Byte = 0
       j=i
         ^

toXxx类型

将字符串的字面值尝试转换为值类型

scala> var i=0
i: Int = 0

scala> var j="123"
j: String = 123

scala> i=j
<console>:13: error: type mismatch;
 found   : String
 required: Int
       i=j
         ^

scala> i=j.asInstanceOf[Int]
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integ
er
  at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:101)

scala> i=j.toInt
i: Int = 123
  ... 32 elided

元组

由多个元素组成的复合变量称为元组,元组的值都是只读的,元组的元素最多不可以超过22个

scala> var t=(1,"zs",false)
t: (Int, String, Boolean) = (1,zs,false)

scala> t._2
res0: String = zs

scala> t._2="lisi"
<console>:12: error: reassignment to val
       t._2="lisi"
           ^

数组

scala> var a=new Array[Int](4)
a: Array[Int] = Array(0, 0, 0, 0)

scala> var a=Array(1,2,3,4)
a: Array[Int] = Array(1, 2, 3, 4)

scala> a(0)= -1

scala> a
res4: Array[Int] = Array(-1, 2, 3, 4)

scala> a.length
res5: Int = 4

scala> a.size
res6: Int = 4

Unit

Unit是一种特殊的值类型,该类型是一个空的元组,通常作为函数的返回值,等价于Java中的void关键字

scala> var u:Unit=()
u: Unit = ()

分支循环

if条件分支

语法

if(条件){
  
}else if(条件){

}
...
else{

}
var a=28
if(a<=10){
    println("child")
}else if(a<=20){
    println("boy|girl")
}else{
    println("man|woman")
}

和Java不同,if 可以将代码块的返回值返回给一个变量

var a=28
var result=if(a<=10){
    "child"
}else if(a<=20){
    "boy|girl"
}else{
    "man|woman"
}
println(s"结果:${result}")

while、do-while

while(条件){
  //循环体
}

在scala语言中while和do-while没有continue和break关键字

var a=5
while (a>0){
    print("\t"+a)
    a -= 1
}
---
do{
    print("\t"+a)
    a -= 1
}while(a>0)

Breaks

Scala 语言中默认没有 break 语句,但是在 Scala 2.8 版本以后可以使用另外一种方式来实现 break 语句功能。在循环中使用 break.break() 语句,当程序执行到该语句时,就会中断循环并执行循环体之后的代码块

scala> import scala.util.control.Breaks
import scala.util.control.Breaks

scala> var a=10
a: Int = 10

scala>     var break=new Breaks
break: scala.util.control.Breaks = scala.util.control.Breaks@17eeaaf

scala>     break.breakable({
     |       do{
     |         print("\t"+a)
     |         a -= 1
     |         if(a<=5){
     |           break.break()
     |         }
     |       }while(a>0)
     |     })
        10      9       8       7       6

for循环(重点)

  • 迭代遍历数组
scala> var array=Array(1,2,3,4)
array: Array[Int] = Array(1, 2, 3, 4)

scala> for(item <- array){print(item+"\t")}
1       2       3       4
  • 通过下标遍历数组
scala> var array=Array(1,2,3,4)
array: Array[Int] = Array(1, 2, 3, 4)

scala> for(i <- 0 until array.length) {
     | 		print(array(i))
     | }
  • for可使用多个循环因子
scala> for(i <- 1 to 9;j <- 1 to  i){
     |     print(s"${i}*${j} ="+i*j+"\t")
     |     if(i==j){
     |         println()
     |     }
     | }
1*1 =1
2*1 =2  2*2 =4
3*1 =3  3*2 =6  3*3 =9
4*1 =4  4*2 =8  4*3 =12 4*4 =16
5*1 =5  5*2 =10 5*3 =15 5*4 =20 5*5 =25
6*1 =6  6*2 =12 6*3 =18 6*4 =24 6*5 =30 6*6 =36
7*1 =7  7*2 =14 7*3 =21 7*4 =28 7*5 =35 7*6 =42 7*7 =49
8*1 =8  8*2 =16 8*3 =24 8*4 =32 8*5 =40 8*6 =48 8*7 =56 8*8 =64
9*1 =9  9*2 =18 9*3 =27 9*4 =36 9*5 =45 9*6 =54 9*7 =63 9*8 =72 9*9 =81
  • for和if的使用
scala> for(i<- 0 to 10;if(i%2==0)){
     |      print(i+"\t")
     |    }
0       2       4       6       8       10
  • for和yield关键字实现元素的提取、创建子集(重点)
scala> var a=Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)

scala> var res=for(item<-a) yield item*item
res: Array[Int] = Array(1, 4, 9, 16, 25)

match-case(模式匹配)

在Scala语言中剔除了Java中的switch-case语句,提供了match-case替代方案,该方案不仅可以按照值匹配,还可以按照类型、以及值的结构(数组匹配、元组匹配、case-class匹配等)

  • 值匹配
var a=Array(1,2,3)
var i=a(new Random().nextInt(3))
var res= i match {
case 1 => "one"
case 2 => "two"
case 3 => "three"
case default => null
}
println(res)
  • 类型匹配
var a=Array(100,"张三",true,new Date())
var i=a(new Random().nextInt(4))
var res= i match {
    case x:Int => s"age:${x}"
    case x:String => s"name:${x}"
    case x:Boolean => s"sex:${x}"
    case _ => "啥都不是"
}
println(res)

注意: _表示默认匹配,等价于default关键字

函数 | 方法

def 方法名(参数1:参数类型,...):返回值类型={
   //代码块的最后一行, 默认是方法的返回值,一般可以省略return关键字
}

√标准函数

scala> def sum(x:Int,y:Int):Int={
     |   x+y
     | }
sum: (x: Int, y: Int)Int

一般情况下,如果函数体的最后一行作为函数的返回值,一般可以省略函数的返回值类型,例如:

scala> def sum(x:Int,y:Int)={
     |   x+y
     | }
sum: (x: Int, y: Int)Int

scala> def sum(x:Int,y:Int):Int={
     |   return x+y
     | }
sum: (x: Int, y: Int)Int

如果函数体中有return语句,函数不能省略返回值类型

scala> def sum(x:Int,y:Int)={
     |   return x+y
     | }
<console>:12: error: method sum has return statement; needs result type
        return x+y
        ^

可变长参数

scala> def sum(values:Int*):Int={
     |   var total=0
     |   for( i<- values) total += i
     |   total
     | }
sum: (values: Int*)Int

scala> sum(1,2,3,4,5)
res9: Int = 15

scala> def sayHi(msg:String,names:String*):Unit={
     |   for(name <- names){
     |           println(msg+"\t"+name)
     |   }
     | }
sayHi: (msg: String, names: String*)Unit

scala> sayHi("Hello","zs")
Hello   zs

可变长参数必须放置在最后一位

scala> def sayHi(names:String*,msg:String):Unit={
     |   for(name <- names){
     |           println(msg+"\t"+name)
     |   }
     | }
<console>:11: error: *-parameter must come last
       def sayHi(names:String*,msg:String):Unit={
                 ^

命名参数

scala> def sayHi(name:String,msg:String):Unit={
     |   println(s"${msg}\t${name}")
     | }
scala> sayHi(msg="hello",name="zhangsan")
hello   zhangsan

参数默认值

scala> def sayHi(name:String="未知",msg:String="哈喽"):Unit={
     |   println(s"${msg}\t${name}")
     | }
sayHi: (name: String, msg: String)Unit

scala> sayHi("zhangsan")
哈喽    zhangsan

scala> sayHi(msg="hello")
hello    未知
scala> sayHi("zhangsan","nihao")
nihao   zhangsan

内嵌函数(没有要求)

求阶乘案例

def jc2(num:Int):Int={
    def compute(x:Int):Int={
        if(x>1){
            x*compute(x-1)
        }else{
            1
        }
    }
    compute(num)
}

√柯里化

在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术

def sum1(x:Int,y:Int): Int ={
    x+y
}
def sum2(x:Int)(y:Int): Int ={
    x+y
}

√匿名函数

将定义的标准函数转化为变量表达的形式,这种表达形式称为匿名函数
在这里插入图片描述

scala> def sum(x:Int,y:Int): Int ={
     |     x+y
     |   }
sum: (x: Int, y: Int)Int

scala> sum _
res38: (Int, Int) => Int = <function2>
变量名:  变量类型            变量值
val sum:(Int,Int)=>Int  = (x,y)=> x+y
--
val i:Int=1
val sum = (x:Int,y:Int)=> x+y
--
val i=1
val sum = ((x,y)=> x+y):((Int,Int)=>Int)
--
val i=1:Byte
def sum:(Int,Int)=>Int  = (x,y)=> x+y //lambda表达式
def sum=(x:Int,y:Int)=>  x+y

通过以上写法得知:
1)任意一个函数,都可以转变成函数式变量

2)Scala语言中一切皆对象,因此变量也是对象

函数 = = 特殊变量 (函数变量 | 匿名函数)== 对象

scala> def j=1 //定义的是一个常量函数,而不是变量
j: Int
scala> j=10
<console>:12: error: value j_= is not a member of object $iw
       j=10
       ^

面向对象

object

Scala语言中没有静态类和静态方法,但是Scala可以使用object声明静态类,该静态类的所有方法都可以直接被调用

object JdbcUtil {
  def sayHello():Unit={
    println("你好!")
  }
}
var jdbcUtil1=JdbcUtil
var jdbcUtil2=JdbcUtil
println(jdbcUtil1)
println(jdbcUtil2)
println(jdbcUtil1==jdbcUtil2) //true
jdbcUtil1.sayHello()
JdbcUtil.sayHello()

Class-类

  • 没有默认构造
class Animal {
  def sleep():Unit={
    println("sleep...")
  }
}
val a1=new Animal 
val a2=new Animal
val a3=new Animal()
println(a1==a2) //false

通过class定义的类在创建对象的时候必须使用new关键字

  • 指定默认构造器
class User(name:String) {//默认构造
  def sayHi():Unit={
    println(s"${name}")
  }
}
val user = new User("张三")
user.sayHi()
  • 扩展默认构造
class User(name:String) {//默认构造
    var age:Int= _

    def this(name:String,age:Int){  //扩展构造
        this(name) //代码第一行必须覆盖默认构造器
        this.age=age
    }

    def sayHi():Unit={
        println(s"${name},${age}")
    }
}

必须在扩展构造的第一行显示地调用默认构造方法,扩展默认构造使用this关键字

伴生对象

如果class和object在同一个scala源文件中,则称object User 是class User的伴生对象,伴生对象相比较于其它对象有优先操作class User的权限,比如可以使用伴生对象object User快速创建class User的对象:

  • apply 工厂方法创建类的对象
class User(name:String){
   var age:Int=_
  def this(name:String,age:Int){
    this(name)
    this.age=age
  }
}
object User{
  def apply(name:String): User = new User(name)
  def apply(name: String,age:Int): User = new User(name,age)
}
var u1=new User("zs")   //创建
var u2=new User("zs",18)// 创建
var u3=User("zs")  //调用apply
var u4=User("zs",18)//调用apply

var u5=User //单例对象
var u6=User //单例对象

var u5=User
var u6=User
  • unapply 解码对象的属性
class User(var name:String){
   var age:Int=_
  def this(name:String,age:Int){
    this(name)
    this.age=age
  }
}
object User{
    def unapply(user: User): Option[(String, Int)] = {
        if(user==null) {
            Some(("",0))
        }else{
            Some((user.name,user.age))
        }
    }
    def apply(name:String): User = new User(name)
    def apply(name: String,age:Int): User = new User(name,age)
}
val u=new User("张三1",18)
val User(name:String,age:Int)=u
println(s"${name},${age}")

抽象类

abstract class Animal(name:String) {
  def eat():Unit={
    println(s"${name}会吃...")
  }
  def sleep():Unit
}

Java语法类型,可以有构造方法,但是无法创建对象

特质(Trait)- 接口

trait Flyable {
  def fly():Unit
}
trait Speekable {
    def speek():Unit={
        println("鸟儿会飞")
    }
}

类似Java的接口,没有构造方法,可以有默认方法的实现

继承

class Dog(name:String) extends Animal(name:String) with Speekable {
    override def sleep(): Unit = {
        println(s"${name} 睡觉")
    }

    override def eat(): Unit = {
        println(s"${name} 啃骨头")
    }

    override def speek(): Unit = {
        println(s"${name}汪汪叫")
    }
}

动态混入(了解)

class SmallBird(name:String) extends Animal (name:String){
  override def sleep(): Unit = {
    println(s"${name} 睡觉...")
  }
}
var smallBird=new SmallBird("小麻雀") with Flyable{
    override def fly(): Unit = {
        println("小麻雀会飞了")
    }
}
smallBird.sleep()
smallBird.fly()

强制混入(了解)

trait Flyable {
  this:Animal=> //强制认定所有Flayable的子类,一定是Animal
  def fly():Unit={
    println(s"${name} 会飞")
  }
}

class Parrot(name:String)  extends Animal(name:String) with Flyable {
  override def sleep(): Unit = {
    println(s"${name}睡觉")
  }
}
val parrot = new Parrot("小鹦鹉")
parrot.fly()

self-type(了解)

class Pig(name:String) extends Animal(name:String){
  self=>  //等价  self:Pig=> 
  override def sleep(): Unit = {
    println(self == this)
    println(this.name+" 会睡!")
    println(self.name+" 会睡!")
  }
}

实际上是混入的一种变体形式

case-class

样例类一般用作数据建模,因此样例类的属性都是只读(类似元组),样例类在使用的时候无需使用new关键字(==比较的是内容)

case class User(id:Int,name:String,sex:Boolean)
val u1=new User(1,"zs",true)
val u2=new User(1,"zs",true)
val u3=User(1,"zs",true)
println(u1)
println(u2)

注意:样例类与样例类之间不允许出现继承关系

样例类之间可以实现快速拷贝

val u1=new User(1,"zs",true)
val u2=u1.copy(id=2)
println(u1)//User(1,zs,true)
println(u2)//User(2,zs,true)

函数式变量 | 对象

函数接口

在jdk1.8中提出了一个Functional Interface的概念,如果一个接口里面只能有一个抽象方法,这种类型的接口被称为SAM接口(Single Abstract Method Interface),也被称为函数式接口

@FunctionalInterface
public interface IDemoService {
    public Integer sum(Integer x,Integer y);
}

@FunctionalInterface编译检查,确保该接口中只有一个抽象方法

在jdk1.8中提出lambda表达式,用于表示这种函数式接口

IDemoService demoService1=(Integer x, Integer y) -> x+y;
IDemoService demoService2=(x,y)->x+y;

和Java类似,Scala中也提供了类似于Java当中的Functional Interface,默认情况下,提供了Function022共23个函数式接口,所有的Scala函数或者方法都是Function022的子类,可以使用 _将任意一个标准函数转换为函数式变量

scala> def sum(x:Int,y:Int): Int ={
     |     x+y
     |   }
sum: (x: Int, y: Int)Int

scala> val func=sum _
func: (Int, Int) => Int = <function2>

通常将func称为sum函数的部分应用函数,通常使用部分应用函数表示一个函数对象,不难看出func的字面量是一个<function2>

尝试以下测试:

scala> func.isInstanceOf[Function2[Int,Int,Int]]
res2: Boolean = true

可以看出得到的func确实是Function2的子类(既然func是Function2的子类,一定可以调用Function2的apply方法实现数据的逻辑计算)

scala> func.apply(1,2)
res3: Int = 3

scala> func(1,2)
res4: Int = 3

在Scala中Function0~Function22存在变体写法(lambda写法):

scala> func.isInstanceOf[(Int,Int)=>Int]
res5: Boolean = true

也就意味着:(Int,Int)=>Int 等价于 Function2[Int,Int,Int]

class SumFunc1 extends Function2[Int,Int,Int] {
  override def apply(v1: Int, v2: Int): Int = {
    v1+v2
  }
}
--- 
class SumFunc2 extends ((Int,Int) =>Int) {
  override def apply(v1: Int, v2: Int): Int = {
    v1+v2
  }
}

由于标准函数一般无法作为参数单独传递,因此在Java中如果想要传递一个函数,必须将该函数封装成为一个函数式对象

public static Integer process(IDemoService demoService,Integer x,Integer y){
    return demoService.sum(x,y);
}
Integer process = process((v1, v2) -> v1 + v2, 1, 2);
System.out.println(process);

可以看出使用Java做Lambda非常麻烦,因为所有Lambda的背后都必须有一个Function Interface

object TestScalaLanguage {
  def main(args: Array[String]): Unit = {
     println(process1((v1,v2)=>v1+v2,1,3))
     println(process2((v1,v2)=>v1*v2,1,3))
  }
  def process1(fun:Function2[Int,Int,Int],x:Int,y:Int):Int={
    fun(x,y)
  }
  def process2(fun:(Int,Int)=>Int,x:Int,y:Int):Int={
    fun(x,y)
  }
}
scala> Array(1,2,3).filter(i=>i%2!=0).map(i=>i*i)
res12: Array[Int] = Array(1, 9)

偏函数

偏函数主要适用于处理指定类型的参数数据,通常用于集合处理

val fun=new PartialFunction[Any,Int] {//只处理Int类型元素
    //需要处理的类型
    override def isDefinedAt(x: Any): Boolean = {
      println("isDefinedAt:"+x)
      x.isInstanceOf[Int]
    }
    //应用 函数处理数据
    override def apply(v1: Any): Int = {
      println("apply:"+v1)
      v1.asInstanceOf[Int]+1
    }
  }
val array = Array(1,2,"a",true,3,4,5)
array.collect(fun)
.foreach(item=>print(item+"\t"))

正常用法:

val a:Any=11
if(fun.isDefinedAt(a)){
    fun(a)
}

通常,偏函数还有另外一种写法(表示该偏函数只处理Int类型的数据,如果数据不是Int,系统就抛出异常)

val fun2:PartialFunction[Any,Int] = {case x:Int => x+1}
val array = Array(1,2,"a",true,3,4,5)
array.collect(fun2) //array.collect({case x:Int => x+1}) 
---
val a= for(i<- array;if(fun2.isDefinedAt(i))) yield fun2(i)

可见性(了解)

Scala中的默认可见性为public,所谓默认,即没有在类或者成员前显示的添加 private 或 protected 可见性关键字,默认都是public(虽然默认是public,但是scala中并没有public关键字)

 class Student {
    var id:Int=_
    var name:String =_
   
   def this(id:Int,name:String){
     this()
     this.id=id
     this.name=name
   }
}
var stu=new Student(1,"zs")
println(s"${stu.id}")

private限定

  • private修饰的属性 | 方法

    只能被本类以及伴生对象可见,子类不可见

 class Student {
   private var id:Int=_
   private var name:String =_
   def getName():String={
     name
   }
   def this(id:Int,name:String){
     this()
     this.id=id
     this.name=name
   }
}
object Student{
  def unapply(student: Student): Option[(Int,String)] ={
    Some(student.id,student.name)
  }
}
var stu=new Student(1,"zs")
var Student(id,name)=stu
println(s"${id},${name}")

Scala并不推荐使用私有属性,同时提供公开方法,一般通过伴生对象的unapply解码来获得对象的属性

  • private修饰类

该类的所有成员属性对外皆不可见,包括伴生对象,一旦给一个class加上private修饰就直接将该类包括该类的默认构造方法全部隐藏

 class Student private() { //修饰的是默认构造
    var id:Int=_
    var name:String =_

   def this(id:Int,name:String){ //扩展构造
     this()
     this.id=id
     this.name=name
   }
    def sayHello():Unit={
     println("hello")
   }
}
object Student{
  def apply(id:Int,name:String): Student = new Student(id,name)
  def unapply(student: Student): Option[(Int,String)] ={
    Some(student.id,student.name)
  }
}
 private class Student { //修饰的是类,一般用在内部类中
    //...
 }

采用这种写法,该Student类对外不可见,同修饰内部类

class Master {//师傅
    private class Slave{ //徒弟
    }
    def teach():Unit={
       val slave = new Slave()
       println(slave)
    }
}

protected 限定

  • 修饰属性 | 方法

    可以被子类以及子类的伴生对象可见

class Student {
  protected var id:Int=_
  protected var name:String =_
  
  protected def say():Unit={
    println(s"${name},${id}")
  }
}
class SmallStudent  extends  Student {
    def this(id:Int,name:String){
      this()
      this.id=id
      this.name=name
    }
}
  • 修饰类

该类只能被本包下的子类所继承,在继承的时候 并不继承父类的可见性

package com.dingl.demo09

protected  class Student  { //只可以被本包子类继承,其它包下不可见
  protected var id:Int=_
  protected var name:String =_

  protected def say():Unit={
    println(s"${name},${id}")
  }
}
class SmallStudent  extends  Student {
    def this(id:Int,name:String){
      this()
      this.id=id
      this.name=name
    }

  override  def say(): Unit = { //默认情况下,子类在继承父类的方法时,会继承方法的可见性,覆盖父类方法的可见性
    println(s"${id},${name}")
  }
}

如果子类不覆盖父类的方法,在继承父类方法的时候,也会继承父类方法的可见性

this限定

当被this限定修饰,该方法或者属性只能在本类内部可见,去除伴生对象

class Animal {
  private|protected[this]  var  name:String=_ //去除伴生对象的可见性
  def this(name:String){
    this()
    this.name=name
  }
  def say():Unit={
    println(s"${name}")
  }
}

包限定

package com.dingl.demo11

class Animal {
  private[demo11] def say():Unit={ //所有在demo11包下的Animal类及其子类都可看到say方法,此时     private的限定失去了意义
     println("animal say")
   }
}

常见关键字

final 关键字

修饰类别JavaScala
最终类,没有子类最终类,没有子类
方法不能被覆盖不能被覆盖
属性常量,不允许修改属性不允许被子类遮盖(val属性)
class Animal {
  final val name:String="大黄"
  def say():Unit={
     println(s"${name}")
  }
}
---
class Dog extends  Animal {
   override  val name:String="小黑" //错误
}

√lazy关键字

被lazy修饰的val常量,只有被真正使用时才会被初始化

lazy val num=sum(1,2)
println(s"${num}")

def sum(x:Int,y:Int):Int={
    println("===========")
    x+y
}

sealed关键字

修饰一个类,被sealed修饰的类及其子类必须放置在同一个源文件中

sealed class Message(content:String)
case class SmsMessage(content:String,phone:String) extends Message(content:String)
case class EmailMessage(content:String,email:String) extends Message(content:String)
val messages = Array[Message](SmsMessage("hello","110"),EmailMessage("你好","11@qq.com"))
messages.foreach(message=>{
    message match {
        case m:SmsMessage =>{
            println("收到短信:"+m.phone)
        }
        case m:EmailMessage=>{
            println("收到邮件:"+m.email)
        }
    }
})

隐式转换/注入/增强 - 重点

implicit 变量- 隐式值

一般定义隐式值的目的是为了隐式注入,要求同一个程序的上下文中只能有一种类型的隐式值

scala> implicit var a:Int=100
a: Int = 100

scala> var m=implicitly[Int]  //按照类型注入
m: Int = 100

implicit 修饰参数- 隐式

object MyImplicits {
  implicit var i= 100 //确保隐式值类型 只能有一个
  implicit val f=(x:Int,y:Int)=>x+y
}
def process(x:Int,y:Int)(implicit fun:(Int,Int)=>Int):Int={
    fun(x,y)
}
import com.dingl.demo13.MyImplicits._
var result2=process(1,2)
println(s"${result2}")

implicit 修饰方法- 隐式转换 不兼容变成兼容

def tellTime(date:Date):Unit={
    println(s"${date.toLocaleString}")
}
import com.dingl.demo13.MyImplicits._
tellTime("2019-9-20 16:34:50") // 等价于 tellTime(strDate("2019-9-20 16:34:50")) 
tellTime(new Date())
object MyImplicits {
  implicit def strDate(str:String):Date={//参数表示要转换的类型,返回值表示需要的目标类型
    val sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    sdf.parse(str)
  }
}

implicit 修饰类- 隐式增强 不可能变可能

class Pig {
    def sleep():Unit={
      println("sleep")
    }
    def eat():Unit={
      println("eat")
    }
}
object MyImplicits {
  implicit class PigImplicits(pig:Pig){
    def fly():Unit={
      println("pig 会飞")
    }
  }
}
import com.dingl.demo13.MyImplicits._
val pig = new Pig()
pig.eat()
pig.sleep()
pig.fly() //增强方法

Scala泛型(看懂)

<:上界限定

def keep[T<:Dog](t:T):Unit={
    println(t)
}

要求T必须是Dog或者Dog的子类

>:下界限定

def keep[T >: Dog](t:T):Unit={ 
    println(t)
}

T必须是Dog或者Dog的父类

<%视图限定

class SmallDog(name:String)  extends Dog {
    def speek():Unit={
        println(s"${name} 汪汪叫~")
    }
}
def playWithSmallDog[T<% SmallDog](dog:T):Unit={
    dog.speek()
}
implicit def str2SmallDog(str:String):SmallDog={
    new SmallDog(str)
}
playWithSmallDog("小狗")

强制将T看做成是SmallDog类型,要求用户在调用的时候必须制定一个隐式转换。将T转换为SmallDog

A:T上下文限定

def compare[T:MyOrder](t1:T, t2:T):Unit={
    val myOrder=implicitly[MyOrder[T]]
    myOrder.compareT(t1,t2)
}

表示上下文中一定会有一个隐式值MyOder[T]隐士值。

+A协变

class DogKeeper[+T] {}
var dogKeeper1=new DogKeeper[SmallDog]
var dogKeeper2=new DogKeeper[Dog]
var dogKeeper3=new DogKeeper[Animal]

dogKeeper3=dogKeeper2
dogKeeper2=dogKeeper1

将DogKeeper[Dog]赋值给DogKeeper[Animal]

-A逆变

class DogKeeper[-T] {}
var dogKeeper1=new DogKeeper[SmallDog]
var dogKeeper2=new DogKeeper[Dog]
var dogKeeper3=new DogKeeper[Animal]

dogKeeper2=dogKeeper3
dogKeeper1=dogKeeper2

将DogKeeper[Animal]赋值给DogKeeper[Dog]

A不变

class DogKeeper[T] {}
var dogKeeper1=new DogKeeper[SmallDog]
var dogKeeper2=new DogKeeper[Dog]
var dogKeeper3=new DogKeeper[Animal]

只能将DogKeeper[Dog]赋值给DogKeeper[Dog]

集合/数组(重点)

常见集合数组(了解)

  • Array

scala>  var array=Array(1,2,3,4,5)
array: Array[Int] = Array(1, 2, 3, 4, 5)
scala> array(0)= -1
scala> array(0)
res2: Int = -1
scala> array.length
res4: Int = 5
scala> array.size
res5: Int = 5
  • Range

scala> var range =new Range(0,10,2)
range: scala.collection.immutable.Range = Range(0, 2, 4, 6, 8)

scala> var range= 0 to 10 by 2
range: scala.collection.immutable.Range = Range(0, 2, 4, 6, 8, 10)

scala> var range= 0 until 10 by 2
range: scala.collection.immutable.Range = Range(0, 2, 4, 6, 8)
  • Vector

scala> var vec=Vector(0,10,1)
vec: scala.collection.immutable.Vector[Int] = Vector(0, 10, 1)

scala> vec(1)
res12: Int = 10

scala> vec(2)
res13: Int = 1

scala> for(i<- 0  to 10 by 2) yield i
res15: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 2, 4, 6, 8, 10)
  • Iterator
scala> var it=Iterator(1,2,3)
it: Iterator[Int] = non-empty iterator

scala> for(i<- it) println(i)
1
2
3

scala> for(i<- it) println(i)

scala> var it=Iterator(1,2,3)
it: Iterator[Int] = non-empty iterator

scala> it.size
res21: Int = 3

scala> it.size
res22: Int = 0
  • List (只读)
scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)

scala>     list.size
res0: Int = 5

scala>

scala>     list.+:(-1) //返回新的List,原始数据不变
res1: List[Int] = List(-1, 1, 2, 3, 4, 5)

scala>     list.::(-1) //追加元素
res2: List[Int] = List(-1, 1, 2, 3, 4, 5)

scala>

scala>     list.++(List(0,0)) //向后追加,元素
res3: List[Int] = List(1, 2, 3, 4, 5, 0, 0)

scala>     list.++:(List(0,0))//向前追加,元素
res4: List[Int] = List(0, 0, 1, 2, 3, 4, 5)

scala>     list.:::(List(1,3)) //向前追加 元素
res5: List[Int] = List(1, 3, 1, 2, 3, 4, 5)

scala>

ListBuffer(支持修改)

scala> var listBuffer=new ListBuffer[Int]
listBuffer: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala>     listBuffer.+=(1)//添加元素
res22: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1)

scala>     listBuffer.update(0,-1)//修改0位置为-1

scala>     listBuffer.-=(-1)//删除元素
res24: scala.collection.mutable.ListBuffer[Int] = ListBuffer()

scala> listBuffer.++=(Array(1,2,3,4))
res25: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4)

scala> listBuffer.remove(1)
res26: Int = 2

scala> listBuffer
res27: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 3, 4)

Set(不可变)

scala> var set=Set(1,2,3,4,5,1)
set: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)

scala>     set.+(-1)
res35: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, -1, 4)

scala>     set.size
res36: Int = 5

scala>     set.+=(10)
scala> set
res38: scala.collection.immutable.Set[Int] = Set(5, 10, 1, 2, 3, 4)

Set(可变集合)

scala>  var set=scala.collection.mutable.Set(1,2,3,4,5,1)
set: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 3, 4)

scala>     set.+(-1)
res51: scala.collection.mutable.Set[Int] = Set(1, 5, 2, -1, 3, 4)

scala>     set.size
res52: Int = 5

scala>     set.+=(10) //添加元素,修改自己
res53: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 3, 10, 4)

scala>     println(set.add(1)) //表示添加是否成功
false
scala>     set.remove(1)
res55: Boolean = true
  • HashMap(不可变)
import scala.collection.mutable.HashMap

var hm=HashMap[String,String](("001","zhangsan"),("002","李四"))
//val hm1=Map[String,String](("001","张三"),("002","lisi"))
hm.-("001") //删除key,不修改原始值
hm.+(("003","王五")) //添加值,不修改原始值
//获取Map的值
val value = hm.get("004").getOrElse("没有值")

//迭代key
for(k<-hm.keys){
    println(hm.get(k).getOrElse(""))
}
val size = hm.size
//迭代值
for(i<-hm.values) println(i)
  • HashMap(可变)
var hm=HashMap[String,String](("001","zhangsan"),("002","李四"))
//val hm1=Map[String,String](("001","张三"),("002","lisi"))
hm.-("001") //删除key,不修改原始值
hm.+(("003","王五")) //添加值,不修改原始值
hm.put("004","赵六")
hm.remove("004")
//获取Map的值
val value = hm.get("004").getOrElse("没有值")
//迭代key
for(k<-hm.keys){
    println(hm.get(k).getOrElse(""))
}
val size = hm.size
//迭代值
for(i<-hm.values) println(i)

集合计算(必须掌握)

为何要学习Scala集合计算?
在这里插入图片描述

算子学习

参考:https://blog.csdn.net/weixin_38231448/article/details/89354185

√ filter算子

用于对集合数据List[T]做过滤,需要传递一个 fn: T => Boolean

scala> List(1,2,3,4,5).filter(item => item %2 ==0) //List(1,2,3,4,5).filter(_ % 2 ==0)
res11: List[Int] = List(2, 4)

scala> val list=List("hello ni hao","hello world","hello scala")
list: List[String] = List(hello ni hao, hello world, hello scala)

scala> list.filter(item=> item.contains("scala"))// list.filter(_.contains("scala"))
res13: List[String] = List(hello scala)

还有一个filterNot算子和filter相反,将满足条件的元素去除。

scala> List(1,2,3,4,5).filterNot(_ % 2 ==0)
res19: List[Int] = List(1, 3, 5)
flatten

用作数组数据降维,例如List[Array[T]] 通过flatten转换可以得到List[T]

scala> val list=List(Array(1,2,3),Array(4,5))
list: List[Array[Int]] = List(Array(1, 2, 3), Array(4, 5))

scala> list.flatten
res21: List[Int] = List(1, 2, 3, 4, 5)
√ map算子

用作数组元素的转换List[T]集合需要提供 fun:T=>U将List[T]转换为List[U]

scala> List("a","b","c").map(item=> (item,1))
res22: List[(String, Int)] = List((a,1), (b,1), (c,1))

scala> val words=List("this is a demo","hello scala").map(line=>line.split(" ")).flatten
words: List[String] = List(this, is, a, demo, hello, scala)
scala> words.map(word=>(word,1))
res27: List[(String, Int)] = List((this,1), (is,1), (a,1), (demo,1), (hello,1),
(scala,1))
√flatMap等价 1.map 2. flatten

专门用于将集合中的元素先进行map转换 List[T] ,尝试将元素T转换为List[U],一般需要提供fun: T =>List[U],这样原始的List[T]就变成List[List[U]],然后该算子会执行flatten将List[List[U]]展开成为List[U]

scala> val lines=List("this is a demo","hello scala")
lines: List[String] = List(this is a demo, hello scala)

scala> val words=lines.flatMap(line=>line.split(" "))
words: List[String] = List(this, is, a, demo, hello, scala)


scala> val linesplits=lines.map(line=> line.split(" "))
linesplits: List[Array[String]] = List(Array(this, is, a, demo), Array(hello, sc
ala))

scala> linesplits.flatten
res36: List[String] = List(this, is, a, demo, hello, scala)

√sort算子

sorted

scala> val nums = List(2,3,5,1,4,6)
nums: List[Int] = List(2, 3, 5, 1, 4, 6)

scala> nums.sorted
res37: List[Int] = List(1, 2, 3, 4, 5, 6)

scala>  nums.sorted(new Ordering[Int]{
     |       override def compare(x: Int, y: Int): Int = {
     |         (x-y) * -1
     |       }
     |     })
res39: List[Int] = List(6, 5, 4, 3, 2, 1)

sortBy

scala> var users=List((1,"zs",18),(2,"lisi",20))
users: List[(Int, String, Int)] = List((1,zs,18), (2,lisi,20))

scala> users.sortBy(user=>user._3)
res41: List[(Int, String, Int)] = List((1,zs,18), (2,lisi,20))

scala> users.sortBy(user=>user._3)(new Ordering[Int]{
     |       override def compare(x: Int, y: Int): Int = {
     |         (x-y) * -1
     |       }
     |     })
res42: List[(Int, String, Int)] = List((2,lisi,20), (1,zs,18))

sortWith

scala> var users=List((1,"zs",18),(2,"lisi",20))
users: List[(Int, String, Int)] = List((1,zs,18), (2,lisi,20))

scala> users.sortWith((u1,u2)=> u1._3 > u2._3)
res45: List[(Int, String, Int)] = List((2,lisi,20), (1,zs,18))

scala> users.sortWith((u1,u2)=> u1._3 < u2._3)
res46: List[(Int, String, Int)] = List((1,zs,18), (2,lisi,20))
√groupBy
scala> val list=List("a","b","a","b","c")
list: List[String] = List(a, b, a, b, c)

scala> list.groupBy(c=>c)
res47: scala.collection.immutable.Map[String,List[String]] = Map(b -> List(b, b)
, a -> List(a, a), c -> List(c))

有如下数组:List(“this is a demo”,"good good study ",“day day up”,"come on baby "),请输出格式数据

List((this,1),(good,2),…)

scala> val lines=List("this is a demo","good good study ","day day up","come on
baby")

scala> val wordpair=lines.flatMap(line=>line.split(" ")).map(word=>(word,1))
wordpair: List[(String, Int)] = List((this,1), (is,1), (a,1), (demo,1), (good,1)
, (good,1), (study,1), (day,1), (day,1), (up,1), (come,1), (on,1), (baby,1))

scala> val group=wordpair.groupBy(word=>word._1).toList
group: List[(String, List[(String, Int)])] = List((this,List((this,1))), (demo,L
ist((demo,1))), (is,List((is,1))), (good,List((good,1), (good,1))), (up,List((up
,1))), (a,List((a,1))), (come,List((come,1))), (on,List((on,1))), (baby,List((ba
by,1))), (day,List((day,1), (day,1))), (study,List((study,1))))                                                             
scala> group.map(t=>(t._1,t._2.size))
res53: List[(String, Int)] = List((this,1), (demo,1), (is,1), (good,2), (up,1),
(a,1), (come,1), (on,1), (baby,1), (day,2), (study,1))

sum

只能针对数值类型的数组做计算

scala> List(1,2,4,5).sum
res57: Int = 12
count

计算数组中数据的个数

scala> List("a","c","c").count(item=>true)
res63: Int = 3
max|min|maxBy|minBy
scala> List(1,3,4,5,6).max
res65: Int = 6

scala> List(1,3,4,5,6).min
res66: Int = 1

scala> List(("a",1),("a",2),("c",3)).maxBy(t=>t._2)
res68: (String, Int) = (c,3)

scala> List(("a",1),("a",2),("c",3)).maxBy(t=>t._1)
res69: (String, Int) = (c,3)

scala> List(("a",1),("a",2),("c",3)).minBy(t=>t._2)
res70: (String, Int) = (a,1)
√reduce

在这里插入图片描述

scala> List(1,2,3,4).reduce((v1,v2)=> v1+v2)//scala> List(1,2,3,4).reduce(_+_)
res71: Int = 10

√aggregate在这里插入图片描述
scala> val ints = List(1,2,3,4,5,6)
ints: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> val tuple = ints.aggregate((0.0,0))((z,v)=>(z._1+v,z._2 +1),(b1,b2)=>
(b1._1+b2._1,b1._2+b2._2))
tuple: (Double, Int) = (21.0,6)

scala> var avg=tuple._1/tuple._2
avg: Double = 3.5
√fold

在这里插入图片描述

scala> val ints = List[Int]()
ints: List[Int] = List()

scala> ints.fold(0)((v1,v2)=>v1+v2)
res2: Int = 0

scala> val ints = List[Int](1,2,3,4)
ints: List[Int] = List(1, 2, 3, 4)

scala> ints.fold(0)((v1,v2)=>v1+v2)
res4: Int = 10
字符统计
scala> var arrs=Array("this is a demo","good good study","day day up")
arrs: Array[String] = Array(this is a demo, good good study, day day up)

scala> arrs.flatMap(line=>line.split(" "))
		   .groupBy(word=>word).toList
           .map(t=>(t._1,t._2.size))
           .sortBy(t=>t._2)

res18: List[(String, Int)] = List((this,1), (demo,1), (is,1), (up,1), (a,1), (st
udy,1), (good,2), (day,2))


scala> arrs.flatMap(line=>line.split(" "))
			.map((_,1))
			.groupBy(t=>t._1)
			.toList.map(t=>(t._1,t._2.map(_._2).sum))
			.sortBy(t=>t._2)

res19: List[(String, Int)] = List((this,1), (demo,1), (is,1), (up,1), (a,1), (st
udy,1), (good,2), (day,2))

y

scala> List(1,3,4,5,6).max
res65: Int = 6

scala> List(1,3,4,5,6).min
res66: Int = 1

scala> List(("a",1),("a",2),("c",3)).maxBy(t=>t._2)
res68: (String, Int) = (c,3)

scala> List(("a",1),("a",2),("c",3)).maxBy(t=>t._1)
res69: (String, Int) = (c,3)

scala> List(("a",1),("a",2),("c",3)).minBy(t=>t._2)
res70: (String, Int) = (a,1)
√reduce

在这里插入图片描述

scala> List(1,2,3,4).reduce((v1,v2)=> v1+v2)//scala> List(1,2,3,4).reduce(_+_)
res71: Int = 10

√aggregate

在这里插入图片描述

scala> val ints = List(1,2,3,4,5,6)
ints: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> val tuple = ints.aggregate((0.0,0))((z,v)=>(z._1+v,z._2 +1),(b1,b2)=>
(b1._1+b2._1,b1._2+b2._2))
tuple: (Double, Int) = (21.0,6)

scala> var avg=tuple._1/tuple._2
avg: Double = 3.5
√fold

在这里插入图片描述

scala> val ints = List[Int]()
ints: List[Int] = List()

scala> ints.fold(0)((v1,v2)=>v1+v2)
res2: Int = 0

scala> val ints = List[Int](1,2,3,4)
ints: List[Int] = List(1, 2, 3, 4)

scala> ints.fold(0)((v1,v2)=>v1+v2)
res4: Int = 10
字符统计
scala> var arrs=Array("this is a demo","good good study","day day up")
arrs: Array[String] = Array(this is a demo, good good study, day day up)

scala> arrs.flatMap(line=>line.split(" "))
		   .groupBy(word=>word).toList
           .map(t=>(t._1,t._2.size))
           .sortBy(t=>t._2)

res18: List[(String, Int)] = List((this,1), (demo,1), (is,1), (up,1), (a,1), (st
udy,1), (good,2), (day,2))


scala> arrs.flatMap(line=>line.split(" "))
			.map((_,1))
			.groupBy(t=>t._1)
			.toList.map(t=>(t._1,t._2.map(_._2).sum))
			.sortBy(t=>t._2)

res19: List[(String, Int)] = List((this,1), (demo,1), (is,1), (up,1), (a,1), (st
udy,1), (good,2), (day,2))
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值