Scala从入门到精通

第一章

1. scala简介

scalable language,运行在jvm上,面向对象和面向函数式编程。

兼容java,可以访问庞大的java类库

2. scala与java对比

执行流程

Scala从入门到精通_第1张图片

3. scala环境搭建

IDEA插件下载地址:http:/.plugins.jetbrains.com/plugin/1347-scala

版本必需和IDEA保持一致

下载插件后,IDEA使用从本地安装插件

4. scala解释器

cmd -> scala

(1)hello world

第二章

2.1 输出语句和分号

1. 输出语句

  换行输出:println

  不换行输出:print

  输出多个值:println(value1, value2, value3...)

2. 分号

  可以写,也可以不写

2.2 常量

1. 分类

(1)字面常量:整型常量(如:2),浮点型常量(如:1.2),字符常量(如:'a'),字符串常量(如:"abc"),布尔常量(如:true, false),空常量(如:null)

(2)自定义常量

2.3 变量

1. 语法格式

val/var 变量名:变量类型 = 初始值

其中:

val定义的是不可重新赋值的变量,也就是自定义常量

var定义的是可以重新赋值的变量

2. 示例

定义一个变量保存一个人的名字“tom”

val name:String = "tom"

3. 类型推断

val name = "tom"

2.3 字符串

三种定义方式:

(1)使用双引号

(2)使用插值表达式

(3)使用三引号

1. 使用双引号

var name = "hadoop"
println(name + name.length) //hadoop6

2. 使用插值表达式

如果涉及大量字符串的拼接,使用插值表达式

val/var 变量名 = s"${变量/表达式}字符串"

示例:定义变量保存“zhagnsan”, 23, "male",定义字符串打印输出:name=zhangsan, age=23, sex=male

val name = "zhangsan"
val age = 23
val sex = "male"
val info = s"name = ${name}, age = ${age}, sex = ${sex}"
println(info) //name = zhangsan, age = 23, sex = male

3. 使用三引号

如果涉及大段文本

val sql = """
     select *
     from stu
     where name = 'zhangsan'
     and age = 23
     order by addr;
     """
println(sql)

4. 惰性赋值

lazy val/var 变量名 = 表达式

2.4 标识符

1. 变量或方法名:小驼峰命名法

2. 类或特质:大驼峰命名法

3. 包:全部小写,多级目录使用"."隔开

2.5 数据类型

Scala从入门到精通_第2张图片

 1. 类型继承图

Scala从入门到精通_第3张图片

(1)Any:所有类型的父类,相当于java中的Object类

(2)AnyVal:所有数值类型的父类

(3)AnyRef:所有引用类型的父类

(4)Unit:相当于java中的void

(5)Null:所有引用类型的子类,它的值只有null

(6)Nothing:所有数据类型的子类,它一般结合异常来进行使用

Scala从入门到精通_第4张图片

 2. 判断是否有误

val b:Int = null //报错,Int是数值类型,null是引用类型

2.6 类型转换

1. 强制类型转换

val/var 变量名:数据类型 = 具体的值.toXXX
例如:
var age = 3.14.toInt //3

2. 值类型数据转成字符串类型数据

val/var 变量名:String = 值类型数据 + ""
val/var 变量名:String = 值类型数据.toString

3. String类型转换成值类型数据

(1)转成Char的方法是“.toCharArray”

2.7 键盘录入

1. 使用步骤

(1)导包:import scala.io.StdIn

(2)通过StdIn.readxxx()来接收用户录入的数据:StdIn.readLine(), StdIn.readInt ()

第三章

3.1 算术运算符

1. 字符串与整数使用乘法计算,相当于字符串拷贝n份

2. 取模运算:a % b = a - a / b * b (10 % 3 = 1, -10 % 3 = -1, 10 % -3 = 1)

3.2 赋值运算符

3.3 关系运算符

Scala从入门到精通_第5张图片

val s1 = "abc"
val s2 = "abc"
println(s1 == s2, s1.eq(s2))  //true, false

3.4 逻辑运算符

3.5 位运算符

原码,反码和补码

计算机底层存储,操作和运算数据都是采用数据的二进制补码形式实现

正数:原码,反码和补码都一样,不需要计算

负数:

   反码计算规则:原码的符号位不变,数值位按位取反

   补码计算规则:反码 + 1

第四章

4.1 流程控制结构

4.2 分支结构

1. scala没有三元表达式

2. scala条件表达式有返回值(java不行)

val sex = "male"
val result = if(sex == "male") 1 else 0
println(result)  //1

3. 块表达式

使用"{}"表示一个块表达式,它和条件表达式一样具有返回值,值为最后一个表达式

val a = {
       var b = "aaa"
       b + "11"
     }
print(a) //aaa11

4.3 循环结构

1. for循环

for(i <- 表达式/数组/集合) {
    //逻辑代码
}
var num = 1 to 10
for(i <- num) {
     println("num: " + i)
}
/**
num: 1
num: 2
num: 3
num: 4
num: 5
num: 6
num: 7
num: 8
num: 9
num: 10
*/
for(i <- 1 to 3; j <- 1 to 5) if(j == 5) println("*") else print("*")
/**
*****
*****
*****
*/

2. 守卫

for表达式中,可以添加if判断语句,这个if判断语句称为“守卫”,每一次遍历时都会经过if判断,如果为true,才会执行for大括号中的逻辑代码

for(i <- 表达式/数组/集合 if 表达式) {
    //逻辑代码
}
for(i <- 1 to 10 if i % 3 == 0){
    println(i)
}
//3 6 9

3. for推导式

在scala中,for循环是有返回值的,可以使用yield表达式构建处一个集合。使用yield的for表达式称为“推导式”。

val result = for(i <- 1 to 10) yield i *10
println(result) //(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)

4. scala中没有break和continue

第五章

5.1 方法

1. 语法格式

def 方法名(参数名:参数类型, 参数名:参数类型) : [return type] = {方法体}

(1)参数列表的参数类型不能省略

(2)返回值类型可以省略

(3)返回值可以不写return,默认就是{}块表达式的值

2. 示例

获取两个数字中的最大值

def getMax(a:Int, b:Int):Int = if(a > b) a else b
println(getMax(3, 13)) //13

3. 返回值类型推断

如果定义的是递归方法,那么不能省略返回值类型

4. 惰性方法

当记录方法返回值的变量被声明为lazy时,方法的执行将被推迟,直到首次使用该值时,方法才会被执行,这种方法叫惰性方法。

java中没有提供惰性技术,但是可以通过懒加载来实现;

lazy不能修饰var类型的变量。

使用场景:

打开数据库连接

提升某些特定模块的启动时间

确保对象中的某些字段能优先初始化

def getTotal(a:Int, b:Int) = a + b
lazy val total = getTotal(1, 2) //这里方法不会被执行
println(total) //3, 这里才回值还行方法

5. 方法参数

(1)默认参数:在定义方法时,可以给参数定义一个默认值

def getSum(a:Int = 10, b:Int = 20) = a + b
println(getSum())       //30
println(getSum(50))     //70
println(getSum(b=50))   //60
println(getSum(50, 10)) //60

(2)带名参数

在调用方法时,指定参数名称来进行调用

(3)变长参数

如果方法的参数是不固定的,可以将该方法的参数定义成变长参数

def 方法名(参数名:参数类型*):返回值类型={方法体}

1)在参数后面加一个*,表示该参数可以是0个或多个

2)一个方法有且只有一个变长参数,并且要位于参数列表的最后

def getSum(numbers:Int*)=numbers.sum //numbers底层为数组,scala的数组可以直接求和
println(getSum(1, 2, 3, 4, 5)) //15

6. 方法调用方式

(1)后缀调用法

和java一样,语法如下:

对象名.方法名(参数)

示例:

Math.abs(-1)

(2)中缀调用法

语法格式:

对象名 方法名 参数

示例:

Math abs -1      //等同Math.abs(-1)
Math min(1, 2)   //等同Math.min(1, 2)
1 + 2            //等同 1.+(10)
1 to 10          //等同 1.to(10)

在scala中,操作符也是方法,例如+号是个方法名,是符号的方法

(3)花括号调用法(只能用于只有一个参数的方法)

语法格式:块表达式的返回值作为入参

Math.abs {
    //表达式
}

示例:

Math.abs{
  val a = -11
  if(a > 0) a else -10
} //10

(4)无括号调用法

如果方法没有参数,可以省略方法名后面的括号

示例:

def sayHello() = println("hello world")
sayHello //hello world

***过程

在scala中,如果方法的返回值类型是Unit,这样的方法称为过程(procedure),过程的"="号可以省略不写,例如:

(1)示例1
def sayHello() {println("hello world")}
sayHello //hello world

(2)示例2
def getMax(a:Int, b:Int) {
  val max = if(a >= b) a else b
  println("max value is: " + max)
}

getMax(1, 2) //max value is: 2

5.2 函数

1. 定义函数

val 函数变量名 = (参数名:参数类型, 参数名:参数类型...) => 函数体

1)在scala中,函数是一个对象

2)类似于方法,函数也有参数列表和返回值

3)函数定义不需要使用def

4)无需指定返回值类型

示例:

(1)示例1
val sum = (a:Int, b:Int) => a + b
sum(1, 2)

(2)示例2
val abs = (a:Int) => {
  if(a > 0) a
  else
    -a
}
abs(-3)

(3)示例3
val hello = () => println("hello")
hello()

5.3 方法和函数的区别

1. 区别

java中两者一致,但在scala中:

1)方式是隶属于类或者对象的,在运行时,它加载到JVM方法区中

2)可以将函数对象赋值给一个变量,在运行时,它加载到JVM堆内存中

3)函数是一个对象,继承自FunchtionN,函数对象有apply, curried, toString, tupled这些方法,而方法则没有

4)函数是对象,方法隶属于对象,所以可以理解为:方法归属于函数

2. 方法转换为函数

有时候需要将方法转换成函数,例如作为变量进行传递

格式:

val 变量名 = 方法名 _ //方法名 + 空格 + 下划线

示例:

def getSum(a:Int, b:Int) = a + b
def sum = getSum _
val a = sum(1, 2) //3

第六章

1. 类和对象

1.1 相关概念

类,对象

1.2 创建类和对象

object(单例对象)/class创建类,new创建对象

示例:

创建一个Person类,并创建它的对象,然后打印

object Demo01 {
  class Person {
  }
  //main方法,所有程序测主入口,所有代码的执行都是从这里开始的
  def main(args: Array[String]): Unit = {
    val person = new Person()
    println(person)
  }
}

简写形式

1. 如果类是空的,没有任何成员,可以省略{}

2. 如果构造器的参数为空,可以省略()

object Demo01 {
  class Person
  
  def main(args: Array[String]): Unit = {
    val person = new Person
    println(person)
  }
}

2. 创建和访问成员变量

object FieldDemo {

  class Person {
    var name : String = ""
    var age : Int = 23
  }

  def main(args: Array[String]): Unit = {
    val person = new Person
    person.name = "Tom"
    person.age = 35
    println(person.name + ": " + person.age) //Tom: 35
  }
}

3. 使用下划线初始化成员变量

(1)用法:

在定义var类型的成员变量时,可以使用"_"来初始化成员变量

String => null

Int => 0

Bolean => false

Double => 0.0...

val变量必需手动初始化

object FieldDemo {

  class Person {
    //1.普通写法
//    var name : String = ""
    //2. 类型推断
//    var name = ""

    //3. 下划线初始化var类型变量, 必需指定类型
    var name : String = _

    var age : Int = _

  }

  def main(args: Array[String]): Unit = {
    val person = new Person
    person.name = "Tom"
    person.age = 35
    println(person.name + ": " + person.age)
  }
}

4. 定义和访问成员方法

(1)格式

def 方法名(参数1:数据类型1, 参数2:数据类型2):[return type] = {//方法体}

(2)示例

object CustomerDemo {

  class Customer {

    var name : String = _
    var sex : String = _

    def sayHello() = println(s"Hello ${name}, your are ${sex}")

  }

  def main(args: Array[String]): Unit = {
    val customer = new Customer
    customer.name = "Tom"
    customer.sex = "male"

    customer.sayHello()
  }

}

5. 访问权限修饰符

在scala中,没有public关键字,没有被private或protected修饰的成员都是public的

也就是scala中只有:private,private[this],protected和默认4中权限修饰符

object PersonDemo {

  class Person {

    private var name : String = _
    private var age : Int = _

    def getName() : String = this.name
    def getAge() : Int = this.age
    def setName(name : String) : Unit = this.name = name
    def setAge(age : Int) : Unit = this.age = age

    def sayHello(msg : String) = println(s"hello ${this.name}, your are ${this.age} years old, ${msg}")
  }

  def main(args: Array[String]): Unit = {

    val person = new Person
    person.setAge(23)
    person.setName("Jim")

    person.sayHello("see you!")

  }
}

6. 类的构造器

6.1 主构造器

主构造器默认帮我们定义好了成员变量

class 类名(var/val 参数名:类型 = 默认值, var/val 参数名:类型 = 默认值...) {//代码块}
object ConstructorDemo {

  class Person(name : String = "John", age : Int){

    println("I am constructor function")

    var addr : String = _

    def sayHello(msg : String) = println(s"hello ${name}, your are ${age} years old, your addr is ${addr}, ${msg}")

  }

  def main(args: Array[String]): Unit = {

    val p1 = new Person(age = 12)
    p1.addr = "sh"
    p1.sayHello("bye")
    println("---------------")

    val p2 = new Person("Tomas",  15)
    p2.sayHello("byeBye")
    println("---------------")

    val p3 = new Person("Jimmy", 18)
    p3.addr = "SZ"
    p3.sayHello("goodBye")

  }

}

6.2 辅助构造器

def this(参数名:类型){
    //调用主构造器或其他构造器
    //构造器代码
}

示例:

object CustomerDemo2 {
  class Customer(val name : String, val addr : String){
    def this(args : Array[String]){
      this(args(0), args(1))
    }
  }
  def main(args: Array[String]): Unit = {
    val c = new Customer(Array("Joy", "Beijing"))
    println(c.name, c.addr)
  }
}

7. 单例对象

scala中没有static关键字,要想定义static变量或者static方法,就要使用scala中的单例对象,也就是object

7.1 定义单例对象

单例对象表示全局仅有一个对象,也就孤立对象

object 单例对象名{}

单例对象中定义的变量是静态变量,在内存中只有一个对象,可以使用“单例对象名.变量名”来访问

object ObjectDemo {

  object Dog {
    val legs = 4
  }

  def main(args: Array[String]): Unit = {
    println("dog has " + Dog.legs + " legs")
  }
}

7.2 定义单例对象方法

object ObjectDemo {
  object Dog {
    val legs = 4
    def printSpliter() = {println("-" * 15)}
  }

  def main(args: Array[String]): Unit = {
    println("dog has " + Dog.legs + " legs")
    Dog.printSpliter()
  }
}

8. main方法

8.1 定义main方法

main方法必需定义在object中,因为scala没有静态方法

def main(args: Array[String]): Unit = { //代码块 }

8.2 继承App特质

创建一个object,继承App特质(Trait),然后将需要编写的代码写在object的构造方法体内

object AppTraitDemo extends App {
  println("Hello main")
}

9. 伴生对象

在java中,经常会有一些类,同时具有实例成员也有静态成员(没有实现静态内容和非静态内容的分离)。在scala中,要实现类似的效果,就需要使用伴生对象。

9.1 定义伴生对象

一个class和object具有相同的名字,这个object称为伴生对象,这个class称为伴生类

(1)伴生对象和伴生类具有相同的名字

(2)伴生对象和伴生类在同一个scala源文件中

(3)伴生对象和伴生类可以相互访问private属性

实例:

object ComponionDemo {

  class Generals {
    def toWar() = println(s"武士拿着${Generals.arms}上阵杀敌")
  }

  object Generals {
    private val arms = "尚方宝剑"
  }

  def main(args: Array[String]): Unit = {
    val g = new Generals
    g.toWar() //武士拿着尚方宝剑上阵杀敌
  }
}

9.2 private[this]访问权限

如果某个成员权限设置为private[this],表示只能在当前类中访问,伴生对象也不可访问

9.3 apply方法

scala支持创建对象时免new操作,要想实现免new,就要通过半生对象的apply方法来实现

格式:

object 伴生对象名 {
    def apply(参数名:参数类型...) = new 类(...)
}

创建对象:

val 对象名 = 伴生对象名(参数1...)

示例:

object ApplyDemo {

  class Person(var name : String, var age: Int){

    println("I am structor")

  }

  object Person {

    def apply(name : String, age: Int) = new Person(name, age);
  }

  def main(args: Array[String]): Unit = {
    val p = Person("John", 23)

    println(p.name + ", " + p.age)
  }

}

第七章

1. 继承

(1)类继承

(2)单例对象继承类

object ObjectExtendsDemo {

  class Person {

    var name : String = _
    var age : Int = _

    def sayHello: Unit = println("hello " + name + ": your age is " + age)
  }

  object Student extends Person

  def main(args: Array[String]): Unit = {

    Student.name = "Tom"
    Student.age = 12

    Student.sayHello //hello Tom: your age is 12
  }

}

单例对象不能继承单例对象,类也不能继承单例对象

(3)重写

重写方法和val变量

object OverrideDemo {

  class Person {
    val name = "Tom"
    var age = 15

    def sayHello: Unit = println(s"Hello ${name}, your age is ${age}")
  }

  class Student extends Person {
    override val name: String = "Alicia"
    age = 25

    override def sayHello: Unit = {
      super.sayHello
      println(".......")
    }
  }

  def main(args: Array[String]): Unit = {
    val s = new Student
    s.sayHello
  }

}

2. 类型判断

2.1 isInstanceOf, asInstanceOf

isInstanceOf用于判断对象是否为指定类的对象

asInstanceOf用于将对象转换为指定类型

格式:

val flag : Boolean = 对象.isInstanceOf[类型]
var 变量 = 对象.asInstanceOf[类型]

2.2 getClass, classOf

object ClassOfDemo {

  class Person

  class Student extends Person

  def main(args: Array[String]): Unit = {
    val s : Person = new Student
    println(s.isInstanceOf[Person])          //true
    println(s.isInstanceOf[Student])         //true
    println(s.getClass == classOf[Person])   //false
    println(s.getClass == classOf[Student])  //true
  }

}

3. 抽象类

如果类中有抽象字段或者抽象方法,那么就是抽象类

抽象字段:没有初始化值的变量

抽象方法:没有方法体的方法

object AbstractDemo {
  abstract class Shape {
    def area():Double
  }
  class Square(var length:Double) extends Shape {
    override def area(): Double = length * length
  }
  class Rectangle(var length:Double, var width:Double) extends Shape {
    override def area(): Double = length * width
  }

  class Circle(radius:Double) extends Shape {
    override def area(): Double = Math.PI * radius * radius
  }
  def main(args: Array[String]): Unit = {
    println(new Square(2).area())  //4.0
    println(new Rectangle(3, 2).area())  //6.0
    println(new Circle(2).area())  //12.566
  }
}

4. 匿名内部类

object DogDemo {

  abstract class Animel {
    def getName : String
  }

  def main(args: Array[String]): Unit = {
    val c = new Animel {
      override def getName() = "dog"
    }.getName()

    println(c)
  }
}

第八章

1. 特质

(1)瘦接口:只有抽象内容的特质

(3)富接口:既有抽象内容,又有具体内容的特质

1.1 语法

定义特质:

trait 特质名称 {
    //普通字段
    //抽象字段

    //普通方法
    //抽象方法
}

继承特质:

class 类 extends 特质1 with 特质2 with 特质3...{
    //重写抽象字段
    //重写抽象方法
}

1.2 代码示例:类和单例对象都可以继承特质,且逻辑一样

object TraitDemo {

  trait Logger {
    def log(msg : String)
  }

  trait Tag1 {
    def addTag1(tag : String)
  }

  trait Tag2 {
    def addTag2(tag : String)
  }

  class ConsoleLogger extends Logger with Tag1 with Tag2 {
    override def log(msg: String): Unit = {
      println(msg)
    }

    override def addTag1(tag: String): Unit = {
      println("tag1 " + tag)
    }

    override def addTag2(tag: String): Unit = {
      println("tag2 " + tag)
    }
  }

  def main(args: Array[String]): Unit = {
    val logger = new ConsoleLogger
    logger.log("hello")
    logger.addTag1("tag1")
    logger.addTag2("tag2")
  }

}

2. 对象混入trait

有时候,我们希望在不改变类继承体系的情况下,对对象的功能进行临时增强或者扩展,这个时候就可以考虑使用对象混入技术。对象混入值得是在scala中,类和特质之间无任何的继承关系,但是通过特定的关键字,却可以让对象具有指定特质中的成员。

语法:

val var 对象名 = new 类 with 特质

示例:

object TraitDemo2 {
  trait Logger {
    def log(msg : String) = println(msg)
  }
  class User
  def main(args: Array[String]): Unit = {
    val u = new User with Logger
    u.log("hello")
  }
}

3. trait构造机制

(1)特质只有一个无参构造器

(2)一个类继承另一个类,以及多个trait,当创建该类的实例时,它的构造器执行顺序如下:

1)执行父类的构造器

2)安装从左到右的顺序执行trait的构造器

3)如果trait有父构造器,则先执行父trait构造器

4)如果多个trait有相同的父trait,则父trait只执行一次

5)执行子类构造器

object TraitDemo3 {

  trait Logger {
    println("Logger info 2")
  }

  trait LoggerChid1 extends Logger {
    println("LoggerChid1 info 3")
  }

  trait LoggerChid2 extends Logger {
    println("LoggerChid2 info 4")
  }

  class Person {
    println("Person info 1")
  }

  class Student extends Person with LoggerChid1 with LoggerChid2 {
    println("student 5")
  }

  def main(args: Array[String]): Unit = {
    val s = new Student
  }
}

4. trait继承class

第九章

1. 样例类

类似java的POJO

1.1 格式

case class 样例类名([val/var] 成员变量名1:类型1, 成员变量名2:类型2...){}

1)在普通class类前加case,就编程了样例类

2)变量名前的修饰符可以不写,默认是val,如果要指定是var,必需手写
 

1.2 样例类的默认方法

当我们定义一个样例类后,编译器会自动生成一些方法,常用的如下:

1)apply()方法:创建类可以省略new

2)toString()方法:打印属性值而非地址

3)equals()方法:可以使用==类比较变量值

4)hashCode()方法:哈希值

5)copy()方法:可以用来快速创建一个属性值相同的对象,还可以使用带名参数来指定属性值

6)unapply()方法:一般用作提取器

2. 样例对象

case修饰的单例对象,它没有主构造器。主要用在:

1)枚举

2)作为没有任何参数的消息传递

object TraitDemo4 {

  trait SEX

  case object MALE extends SEX

  case object FEMALE extends SEX

  class Person(var name: String, var sex:SEX){

  }

  def main(args: Array[String]): Unit = {
    val p = new Person("Tom", MALE)
    println(p.name, p.sex)
  }

}

第十章

1. 数组

定长数组,变长数组

1.1 定长数组

格式:

val/var 变量名 = new Array[元素类型](数组长度)
val/var 变量名 = Array(元素1, 元素2...)

示例:

object ArrayDemo1 {

  def main(args: Array[String]): Unit = {
    val arr1 = new Array[Int](10)
    arr1(0) = 2
    println(arr1(0))
    println("*" * 15)

    val arr2 = Array("java", "scala", "python")
    for(item <- arr2){
      println(item)
    }
  }
}

2
***************
java
scala
python

1.2 变长数组

import scala.collection.mutable.ArrayBuffer

val/var 变量名 = ArrayBuffer[类型]()
val/var 变量名 = ArrayBuffer(元素1, 元素2...)

(1)创建数组

object ArrayDemo2 {

  def main(args: Array[String]): Unit = {
    val arr1 = ArrayBuffer[Int]()
    println(arr1)
    println("-"*15)

    val arr2 = ArrayBuffer("China", "US", "England")
    println(arr2)
  }
}

ArrayBuffer()
---------------
ArrayBuffer(China, US, England)

(2)变长数组元素的增删改

1)使用+=增加单个元素

2)使用-=删除单个元素

3)使用++=追加一个数组到变长数组中

4)使用--=移出变长数组中的指定多个元素

示例:

object ArrayDemo3 {

  def main(args: Array[String]): Unit = {
    val arr1 = ArrayBuffer("hadoop", "spark", "flink")
    arr1 += "flume"
    arr1 -= "hadoop"

    arr1 ++= Array("hive", "sqoop")
    arr1 --= Array("spark", "sqoop")

    println(arr1)
  }
}

1.3 数组遍历

object ArrayDemo4 {

  def main(args: Array[String]): Unit = {
    val arr1 = Array("a", "b", "c", "d", "e")
    for (item <- 0 to arr1.length - 1) println(arr1(item))
    println("-" * 15)

    for (item <- 0 until arr1.length) println(arr1(item))
    println("-" * 15)

    for (item <- arr1.indices) println(arr1(item))
    println("-" * 15)

    for (item <- arr1) println(item)
  }
}

1.4 数组常用算法

sum(), max(), min(), sorted(), reverse()

2. 元组

元组一般用来存储多个不同类型的值,元组的长度和元素都是不可变的。例如,同时存储姓名,年龄,性别,出生年月这些数据,就要用到元组。

格式:

val/var 元组 = (元素1, 元素2...)
val/var 元组 = 元素1 -> 元素2  //适用于只有两个元素的元组

示例:

object TupleDemo {

  def main(args: Array[String]): Unit = {
    val tuple1 = ("Tom", 23, "2018-11-17")
    val tuple2 = "Tom" -> "Jim"

    println(tuple1)
    println("--------------------------")
    println(tuple2)

  }
}

(Tom,23,2018-11-17)
--------------------------
(Tom,Jim)

元组访问:

方式1:
    元组名._1  //访问第1个元素,序号从1开始
    元组名._2  //访问第2个元素,序号从1开始
方式2:
    for(item <- tuple1.productIterator){
      println(item)
    }

3. 列表

List

3.1 不可变列表

格式:

val/var 变量名 = List(元素1, 元素2...)
val/var 变量名 = Nil  //空列表
val/var 变量名 = 元素1 :: 元素2 :: Nil  //Nil表示结束

3.2 可变列表

格式:

import scala.collection.mutable.ListBuffer
val/var 变量名 = ListBuffer[type]()  //空的可变列表
val/var 变量名 = ListBuffer(ele1, ele2...)

 可变列表操作:

Scala从入门到精通_第6张图片

3.3 列表操作

isEmpty: 判断一个列表是否为空

distinct:去重

++:拼接两个列表,返回一个新的列表

head:获取列表首个元素

tail:获取除首个元素外的其他所有元素

reverse:反转,返回反转后的列表

take:获取前缀元素(具体个数可自定义,比如前3个元素)

drop:获取后缀元素(具体个数可自定义,比如除了前3个元素剩下的所有元素都算后缀元素)

flatten:扁平化操作,返回扁平化后的新列表(针对嵌套列表的操作)

zip:对列表进行拉链操作,将两个列表合并成一个元素为元组列表

unzip:对列表进行拉开操作,将一个包含元组的列表合拆成两个列表的元组

toString:将列表转成默认字符串形式

mkString:将列表转成指定字符串形式

union:获取两个列表的并集,并返回

intersect:获取两个列表的交集,并返回

diff:获取两个列表的差集,并返回

示例:

object ListDemo {

  def main(args: Array[String]): Unit = {

    val nameList = List("zhangsan", "lisi", "wangwu")
    val ageList = List(12, 23, 45)

    val tupleList = nameList.zip(ageList)
    println(tupleList)
    println("---------------------------")

    val tuple = tupleList.unzip
    println(tuple)
  }

}

List((zhangsan,12), (lisi,23), (wangwu,45))
---------------------------
(List(zhangsan, lisi, wangwu),List(12, 23, 45))

4. 集合(SET)

不可变,可变

-,+,++,--

5. Map

val/var map = Map(key1 -> val1, key2 -> val2...)
val/var map = Map((key1, val1), (key2, val2)...)

map(key): 获取对应的值,如果不存在,返回None

map.keys: 返回所有的键

map.values:返回所有的值

+:添加键值对

-:删除键值对

object MapDemo {

  def main(args: Array[String]): Unit = {
    val map = mutable.Map("zhangsan" -> 23)
    map += "lisi" -> 27

    println(map)         //Map(lisi -> 27, zhangsan -> 23)
    println(map.keys)    //Set(lisi, zhangsan)
    println(map.values)  //HashMap(27, 23)
    for((k, v) <- map) println("k : " + k + ", v : " + v)
    //k : lisi, v : 27
    //k : zhangsan, v : 23

  }
}

6. 函数式编程

是指方法的参数列表可以接收函数对象

例如:add(10, 20)不是函数式编程,add(函数对象)是函数式编程

以下函数都可以进行函数式编程:

Scala从入门到精通_第7张图片

 6.1 foreach遍历

def foreach(f:(A) => Unit):Unit
def foreach(函数)

示例:

object FunctionDemo {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)
    list.foreach(item => println(item))
  }

}

 6.2 简化函数定义

1. 类型推断:函数的参数类型可以不写

2. 下划线简化:当函数参数只在函数中出现一次,且函数体没有嵌套调用,可以使用下划线简化函数定义

object FunctionDemo {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)
//    list.foreach(item => println(item))
    list.foreach(println(_))
  }
}

 6.3 映射(map方法)

def map[B](f(A) => B) : TraversableOnce[B]
def map(函数对象)

6.4 扁平化映射(flatMap)

先进行map操作,然后进行flatten操作 

Scala从入门到精通_第8张图片

object FunctionDemo1 {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4)

    val list1 = list.flatMap(item => List(item, item * 2))
    println(list1)
  }
}

6.5 过滤(filter)

6.6 排序

默认排序(sorted),指定字段排序(sortBy),自定义排序(sortWith)

6.7 分组(groupBy)

6.8 聚合

(1)reduce

  def main(args: Array[String]): Unit = {
    val list = (1 to 10).toList
    //x表示聚合的结果,y表示list中遍历的下一个值
    val sum = list.reduce((x, y) => x + y)
    val sum1 = list.reduce(_ + _)
    val sum2 = list.reduceLeft(_ + _)
    val sum3 = list.reduceRight(_ + _)
  }

(2)fold

它是在reduce的基础上加了一个初始值

  def main(args: Array[String]): Unit = {
    val list = (1 to 10).toList
    val fold = list.fold(100) (_ + _)
    println(fold) //155
  }

7 综合练习

  def main (args: Array[String] ): Unit = {
    val stuList = List(("zhangsan", 35, 86, 97), ("lisi", 62, 79, 89), ("wangwu", 85, 79, 53), ("zhaoliu", 100, 100, 100))
    println(stuList)

    //语文及格
    val yuwen = stuList.filter(_._2 >= 60)
    println(yuwen)

    //总成绩
    val total = stuList.map(e => e._1 -> (e._2 + e._3 + e._4))
    println(total)

    //总成绩排名
    val sortedTotal = total.sortWith((x, y) => x._2 > y._2)
    println(sortedTotal)

  }

List((zhangsan,35,86,97), (lisi,62,79,89), (wangwu,85,79,53), (zhaoliu,100,100,100))
List((lisi,62,79,89), (wangwu,85,79,53), (zhaoliu,100,100,100))
List((zhangsan,218), (lisi,230), (wangwu,217), (zhaoliu,300))
List((zhaoliu,300), (lisi,230), (zhangsan,218), (wangwu,217))

第十一章

1. 模式匹配

scala有强大的模式匹配机制,应用包括:

1)判断固定值;

2)类型查询

3)快速获取数据

1.1 简单模式匹配

格式:

变量 match {
    case "val1" => expresstion1
    case "val2" => expresstion2
    case _ => expresstion1  //默认匹配
}

代码:

object MatchDemo {
  def main(args: Array[String]): Unit = {
    println("pls entry a String:")
    val s = StdIn.readLine()

    val res = s match {
      case "hadoop" => "big data framework"
      case "zk" => "zk framework"
      case "spark" => "cal framework"
      case _ => "not matck"
    }

    println(res)
  }
}

pls entry a String:
spark
cal framework

1.2 匹配类型

格式:

变量 match {
    case 变量名1:类型1 => expresstion1
    case 变量名2:类型2 => expresstion2
    case _:类型3 => expresstion3
    case _ => expresstion1  //默认匹配
}

如果 case表达式中没有使用到匹配到的变量,那么可以使用下划线替代变量名

代码:

object MatchDemo1 {
  def main(args: Array[String]): Unit = {
    val a : Any = 1.2
    a match {
      case _:String => println("String type")
      case x:Int => println(x + " is Int type")
      case _:Double => println("Double type")
      case _ => println("not match")
    }
  }
}

1.3 守卫

格式:

变量 match {
    case 变量名1 if 条件1 => expresstion1
    case 变量名2 if 条件2 => expresstion2
    case _ if 条件3 => expresstion3
    case _ => expresstion1  //默认匹配
}

代码:

object MatchDemo2 {
  def main(args: Array[String]): Unit = {
    println("pls enter a Int")
    val s = StdIn.readInt()

    s match {
      case x if x > 0 && x < 10 => println( "0 < x < 10")
      case x if x > 10  => println( "10 < x")
      case _ => println("no match")
    }
  }
}

1.4 匹配样例类

格式:

对象名 match {
    case 样例类型1(f1, f2, fn) => expresstion1
    case 样例类型2(f1, f2, fn) => expresstion2
    case _ => expresstion1  //默认匹配
}

1)字段个数必需与样例类定义的字段个数一致

2)要匹配的对象必需声明为Any

代码:

object MatchDemo3 {

  case class Person(name:String, age:Int)
  case class Dog(age:Int)

  def main(args: Array[String]): Unit = {
    val c : Any = Person("zhangsan", 23)

    c match {
      case Person(a, b) => println(s"this is a Person class, name is ${a}, age is ${b}")
      case Dog(a) => println(s"this is a Dog class, age is ${a}")
      case _ => "not match"

    }
  }
}

1.5 匹配集合

代码:

object MatchDemo4 {

  def main(args: Array[String]): Unit = {
    val arr1 = Array(1, 2, 3)
    var arr2 = Array(0)
    var arr3 = Array(2, 3, 4, 5, 6)

    arr1 match {
      case Array(1, x, y) => println("匹配长度为3,0位置的值为1,其他位置的值任意的数组")
      case Array(0) => println("匹配长度为1,0位置的值为0的数组")
      case Array(2, _*) => println("匹配0位置的值为2,其他位置的值任意,数组长度任意的数组")
      case _ => "not match"
    }
  }
}

1.6 匹配列表

List(0)  //只保存0一个元素的列表
List(1, _*)  //以0开头的列表,长度不限
List(1, x, y)  //以1开头的列表,长度为3

1.7 匹配元组

1.8 变量声明中的模式匹配

代码:

  def main(args: Array[String]): Unit = {
    val  arr1 = (0 to 10).toArray
    //匹配数组的第1,2,3三个元素,并赋值给item1, item2, item3
    val Array(_, item1, item2, item3, _*) = arr1
    println(item1, item2, item3)  //1, 2, 3

    println("*********************")
    val list = (0 to 10).toList
    //获取list的第0,1个元素
    val List(a, b, _*) = list
    val a1 :: b1 :: tail = list
    println(a, b, a1, b1)
  }

1.9 匹配for表达式

  def main(args: Array[String]): Unit = {
    val map = Map("zhagnsan" -> 23, "zhaosi" -> 23, "wangwu" -> 27, "zhaoliu" -> 33)
    for((k, v) <- map if v == 23) println(k + ":" + v)
    for((k, 23) <- map) println(k + ":" + 23)
  }

2. Option类型

Option表示可选值,这种类型的数据有两种形式:

(1)Some(x)表示实际的值

(2)None表示没有值,可以使用getOrElse方法,当为None时,可以指定默认值

object OptionDemo {

  def div(a : Int, b : Int): Option[Int] = {
    if(b == 0) None
    else Some(a / b)
  }

  def main(args: Array[String]): Unit = {
    println(div(2, 0))
  }
}

3. 偏函数

  def main(args: Array[String]): Unit = {
    val pf : PartialFunction[Int, String] = {
      case 1 => "一"
      case 2 => "二"
      case 3 => "三"
      case _ => "未匹配"
    }

    println(pf(1))
    println(pf(2))
    println(pf(3))
    println(pf(4))
  }

一
二
三
未匹配
  def main(args: Array[String]): Unit = {
    val list = (1 to 10).toList
    val res = list.map{
      case x if x >= 1 && x < 4 => "[1-4)"
      case x if x >= 4 && x < 8 => "[4-8)"
      case _ => "[8-*)"
    }

    println(res)  //List([1-4), [1-4), [1-4), [4-8), [4-8), [4-8), [4-8), [8-*), [8-*), [8-*))
  }

4. 正则表达式

格式:

val regname = """reg expression""".r

5. 异常处理

6. 提取器Extractor

(1)将类编程样例类,那么会自动生成unapply方法

(2)实现unapply方法

def unapply(stu : Student) : Option[(type1, type2, ...)] = {
    if(stu != null) Some(f1, f2, ...)
    else None

}

Scala从入门到精通_第9张图片

object ApplyDemo {

  class Student(var name: String, var age:Int)

  object Student {
    def apply(name: String, age: Int): Student = new Student(name, age)

    def unapply(s: Student): Option[(Any, Any)] = if(s == null) None else Some(s.name, s.age)
  }

  def main(args: Array[String]): Unit = {
    val stu = Student("zhangsan", 23)

    println(stu.name, stu.age)
    println("--------------------------")

    val res = Student.unapply(stu)
    println(res)

    println("--------------------------")
    stu match {
      case Student(name, age) => println(s"name = ${name}, age = ${age}")
      case _ => "not match"
    }
  }
}


(zhangsan,23)
--------------------------
Some((zhangsan,23))
--------------------------
name = zhangsan, age = 23

第十二章

1. 读取数据

1.1 按行读取数据

val source : BufferedSource = Source.fromFile("path", "encoding")
val lines : Iterator[String] = source.getLines
val list:List[String] = lines.toList
source.close

代码:

object SourceDemo {
  def main(args: Array[String]): Unit = {
    val source = Source.fromFile("./read.txt" ,"UTF-8")
    val list:List[String] = source.getLines.toList
    println(list)
    source.close
  }
}

1.2 按字符读取数据

格式:

val source : BufferedSource = Source.fromFile("path", "encoding")
val iter : BufferedIterator[Char] = source.buffered
while(iter.hasNext) print(iter.next)
source.close

1.3 读取此法单元和数字

1.4 从URL或其他源中读取数据

val source1 = Source.fromURL("https://www.baidu.com")
val source2 = Source.fromString("Hello")
println(source1.mkString)
println(source2.mkString)

1.5 读取二进制文件

java类库

2. 写入数据

java类库

第十三章

1. 高阶函数

如果一个函数的参数列表可以接收函数对象,那么这个函数就叫高阶函数(High-Order Function)

常用的高阶函数分为:

1)作为值的函数

2)匿名函数

3)柯里化

4)闭包

5)控制抽象

2. 作为值的函数

在scala中,函数就和数字、字符串一样,可以将函数传递给一个方法,例如,可以对算法进行封装,然后将具体的动作传递给方法。

案例:

将一个整数列表中的每个元素转换成对应个数的星号(*)

List(1, 2, 3) => *, **, ***

代码:

  def main(args: Array[String]): Unit = {
    val list1 = (1 to 10).toList
    val func = (x:Int) => "*" * x
    val list2 = list1.map(func)
    println(list2)
  }

3. 匿名函数

  def main(args: Array[String]): Unit = {
    val list1 = (1 to 10).toList
    //    val func = (x:Int) => "*" * x
    //    val list2 = list1.map(func)
    val list2 = list1.map("*" * _)
    println(list2)
  }

4. 柯里化

柯里化(Currying)是指将原来接收多个参数的方法转换为多个只有一个参数的参数列表的过程

Scala从入门到精通_第10张图片

 执行过程:

Scala从入门到精通_第11张图片

 案例:

定义一个方法,完成两个字符串的拼接

代码:

object FuncDemo1 {

  //1. 普通字符串拼接,如果需求变动,例如要将x转换成大写,然后和y进行拼接,就需要修改方法体
  def merge (x:String, y:String): String = x + y

  //2. 柯里化
  def merge1 (x:String, y:String)(f1:(String, String) => String): String = f1(x, y)

  def main(args: Array[String]): Unit = {
    println(merge("a", "b"))

    println(merge1("a", "b")(_.toUpperCase + _))
  

5. 闭包

闭包指的是可以访问不在当前作用域范围数据的一个函数

格式:

val y = 10
val add = (x:Int) => x + y
println(add(5))  //15

代码:

object FuncDemo2 {

  def a = 10

  def getSum(b : Int) = a + b

  def main(args: Array[String]): Unit = {
    println(getSum(3))
  }
}

6. 控制抽象

假设函数A的参数列表需要接收一个函数B,且函数B没有输入值也没有返回值,那么函数A就被称为控制抽象函数

格式:

val 函数A = (函数B: () => Unit) => {
    //代码
    函数B()
}

代码:

object FuncDemo3 {

  def main(args: Array[String]): Unit = {
    val myShop = (f1: () => Unit) => {
      println("hello")
      f1()
      println("Bye")
    }

    myShop(() => println("shopping"))
  }
}

第十四章

1. 隐式转换和隐式参数

1)隐式转换:使用implicit关键字声明的带有单个参数的方法,该方法是被自动调用的,用来实现自动将某种类型的数据转换为另一种类型的数据

2)隐式参数:使用implicit关键字修饰的变量。在scala的方法中,可以带有一个标记未implicit的参数列表,调用该方法时,此参数列表可以不用给初始化值,因为编译器会自动查找缺省值提供给该方法。

需求(手动导入):

让File对象具有read功能,将文件按字符串读取

object ImplicitDemo {

  class RichFile(file: File) {
    def read() = Source.fromFile(file).mkString
  }

  object ImplicitObject {
    implicit def file2RichFile(file: File) = new RichFile(file)
  }

  def main(args: Array[String]): Unit = {
    import ImplicitObject.file2RichFile

    val file = new File("./read.txt")
    println(file.read)
  }

}

2. 自动导入隐式转换

在当前作用域中有隐式转换方法,会自动导入隐式转换

object ImplicitDemo1 {

  class RichFile(file: File) {
    def read() = Source.fromFile(file).mkString
  }

  def main(args: Array[String]): Unit = {
    implicit def file2RichFile(file: File) = new RichFile(file)
    val file = new File("./read.txt")
    println(file.read)
  }

}

3. 隐式参数

手动导入:

object ImplicitDemo2 {

  def show(name:String)(implicit delimit:(String, String)) = delimit._1 + name + delimit._2

  object ImplicitParam {
    implicit val delimit_defaul = "<<<" -> ">>>"
  }

  def main(args: Array[String]): Unit = {
    import ImplicitParam.delimit_defaul
    println(show("zhangsan"))
  }

}

自动导入:

object ImplicitDemo2 {

  def show(name: String)(implicit delimit: (String, String)) = delimit._1 + name + delimit._2

  def main(args: Array[String]): Unit = {
    implicit val delimit_defaul = "<<<" -> ">>>"
    println(show("zhangsan"))
  }

}

第十五章

1. 泛型

scala中泛型使用[数据类型]来表示,一般结合数组或者集合使用,常用的方法还有:

1)泛型类

2)泛型特质

3)泛型方法

1.1 泛型方法

object TypeDemo {
  //向上转类型耗性能
//  def getMidEle(arr:Array[Any]) = arr(arr.length / 2)
  
  //泛型优化
  def getMidEle[T](arr:Array[T]) = arr(arr.length / 2)

  def main(args: Array[String]): Unit = {
    println(getMidEle(Array(1, 2, 3, 4, 5)))
    println(getMidEle(Array("a", "b", "c")))
  }

}

1.2 泛型类

class 类[T] {val 变量名:T}

1.3 上下界

上界: [T <: 类型]  //T只能是对应的类型,或者对应类型的子类型
下界: [T >: 类型]  //T只能是对应的类型,或者对应类型的父类型
上下界:[T >: 类型2 <: 类型1]

2. 协变,逆变,非变

协变:类A和类B是父子类关系,Pair[A]和Pair[B]之间也有父子类关系 class Pair[+T] {}

逆变:类A和类B是父子类关系,但Pair[A]和Pair[B]之间是子父类关系 class Pair[-T] {}

非变:类A和类B是父子类关系,但Pair[A]和Pair[B]之间没有关系 class Pair[T] {}

Scala从入门到精通_第12张图片

你可能感兴趣的:(scala,开发语言,后端)