1、概述

1.1、作者

联邦理工学院(EPFL)的 Martin Odersky,之前曾从事工作是 Generic Java 和 javac(Sun Java 编译器),并于 2001 年开始 设计 Scala。
所有Scala与Java有很多相似之处

1.2、介绍

  • 多范式(multi-paradigm)的编程语言,设计初衷是要集成面向 对象编程和函数式编程的各种特性。
  • 运行在 Java 虚拟机上,并兼容现有的 Java 程序。
  • 源代码被编译成 Java 字节码文件,运行于 JVM 之上,并可以调用 现有的 Java 类库。

    1.3、特点

  • 面向对象特性

    • 一种纯面向对象的语言,每个值都是对象
  • 函数式编程
    • 函数式语言,其函数也能当成值来使用。
    • 提供了轻量级的语法用以定义匿名函数,支持高阶函数, 允许嵌套多层函数,并支持柯里化。
  • 静态类型
    • 具备类型系统,通过编译时检查,保证代码的安全性和一 致性。
    • 像 scala,java,c/c++,c#,golang 等属于静态类型。
    • 像 python,ruby,javascript 等属于动态语言。
  • 扩展性
    • 提供了许多独特的语言机制,可以以库的形式轻易无缝添 加新的语言结构。
  • 并发性
    • 其并没有在底层对语言的并发性做更新升级。
    • 使用 Actor 作为其并发模型

      1.4、版本

      版本为2.11
      开发工具为idea

      1.5、安装教程

  1. 下载地址: https://www.scala-lang.org/download/all.html
  2. 双击安装
  3. 打开idea
  4. 下载插件Scala
  5. 创建Scala项目

    1.6、应用前景

  • 技术方面
    • 完全兼容 Java,运行于 JVM 虚拟机之上
    • 支持函数式编程和类型推断
    • 结合面向过程和面向对象,并保证代码简洁及优雅
    • 开发工具 IDE 非常成熟
  • 应用方面

    • LinkedIn/Twitter/英国卫报等众多企业已全面生产应用 Scala,或替换 Java 代码
    • spark/kafka 等大数据开发组件的巨大爆发力,使 Scala 为国内所热捧

      2、语法

      2.1、基本概念

  • 对象:类的一个具体实例,对象包含属性和方法,如旺财有属性 毛色和看家本领能力

  • 类:类是对象的抽象,对象是类的一个实例
  • 方法:描述类所拥有的行为能力,一个类可以拥有多个方法
  • 属性:也称字段,即每个对象拥有它自身实例变量集合,通过赋 值来创建真正的属性值

    2.2、基本语法

  • 区分大小写

  • 类名:首字母要大写,如 class HelloWorld{},class Person{},class Student{},也称大驼峰
  • 方法名称:首字母小写,从第 2 个单词开启的首字段大写,如 def toString(),def getName(),即为小驼峰
  • 程序文件名:保持与类名或对象名一致,区分大小写,以 “.scala”来结尾
  • 主程序入口:def main(args: Array[String]) ,scala 若要独立运行 必须从 main 方法开始处理,每个 scala 强制程序入口

    2.3、标识符

  • 兼容 java 标识符命名规范

  • 命名规范:类为大驼峰,其它为小驼峰 o 多符号命名:可以加入“$,+,++,<“等符号参与命名,注意首字 符和尾字符的若干限制,如”$”不要作为开头,”_”不要作为结 尾
  • 有新增关键字,如 yield 成为 scala 新关键字,则在 scala 调用 时,则应由 Thread.yield()改成 Thread.yield来使用

    2.4、关键字和注释

    与java一样

    2.5、 换行符

  • 面向行编程的语言,每行语句可以用显式的”;”来结尾,或者以回 车换行来结尾。即末尾的”;”是可选的

  • 如果一行中包括多个语句,则必须用”;”来分隔

    2.6、 包定义

  • 兼容 java 包方式,如 package com.tl.utils;

  • 类 c#的包定义方式 package com.tl.test { class MyTest { } }

    2.7、引用

  • 引入单个类:import java.util.Date;

  • 引入包下所有类:import java.util._;
  • 引入包下若干类(选择器):import java.util.{Date,HashSet,HashMap}
  • 引入类后重命名:import java.util.{Date => OldDate}
  • 隐藏包下的部分成员:import java.util.{Date=>,}
  • 默认包引入为:java.lang.、scala.、Predef._,默认引入的 包的情况下其内类的使用均不需要加上包名

    3、数据类型

    3.1、与Java相似部分

    Byte,Short,Int,Long,Float,Double,Char,String,Boolean
    皆为对象类型,scala 无原生数据类型

    3.2、差异部分

  • Unit:即为空值或无值,与 Java 中的 void 等同

  • Null:即为 null,即空引用
  • Nothing:是任何类型的子类型,在 scala 类层级的最末端
  • Any:是所有其它类的基(父)类
  • AnyRef:是所有引用类的基础,即除了值类型之外
  • AnyVal:是所有值类型的基类,包括 9 个值类型

    • scala.Double
    • scala.Float
    • scala.Long
    • scala.Int
    • scala.Char
    • scala.Short
    • scala.Byte
    • scala.Unit
    • scala.Boolean

      3.3、关系图

      image.png

      3.4、常见字面量

  • 整型字面量:如:0,1,0xff,07L

  • 浮点型字面量:0.0,3.14159f
  • 布尔型字面量:true 或者 false
  • 字符字面量:单引号括起来,如’a’,’b’,’\t’
  • 字符串字面量:双引号括起来,如”HelloWorld”,”MyName”
  • Null 值:是对引用对象类型的子类,不兼容值类型

    4、变量

    4.1、常量

    在程序运行过程中其值不会发生变化的量叫做常量。如:”A”、 “B”、”123”太丰富
    使用 val 来声明常量

    1. val constString:String="hero";
    2. constString="new_hero";

    4.2、变量

    在程序运行过程中其值可能发生改变的量叫做变量。如:对象的 名称、年龄、发色、身材等
    使用 var 来声明变量

    1. var varString:String="name";
    2. varString="new_name";

    4.3、变量声明

    显式声明类型

    1. var variableName : DataType [= Initial Value]
    2. val constName: DataType [= Initial Value]

    隐式声明类型

    1. var myString="HelloWorld";
    2. var myInt=1;

    批量变量声明

    1. var a,b=10;
    2. println(a+b);

    5、访问修饰符

    scala 访问修饰符包括 private,protected,public,对象的访问级别默认都是 public

    5.1、private

  • 仅在包含了成员定义的类或对象内部可见

  • 在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员

    1. class TestPrivate {
    2. class Person {
    3. private def testPrivate() {
    4. println("in private method");
    5. }
    6. def testPublic() {
    7. println("in private method");
    8. }
    9. class Student {
    10. testPrivate(); //正确
    11. }
    12. (new Person()).testPublic() //public 方法访问,正确
    13. (new Person()).testPrivate() //private 方法访问,错误
    14. }

    5.2、protected

    比 java 的 protected 更严格,除了子类可以访问,同包下的类是不能访问的

    1. class TestProtected {
    2. class Animal {
    3. protected def walk() { println("i can walk!") }
    4. }
    5. class Person extends Animal {
    6. walk() //子父类继承的情况下,能访问 proected 修饰的方法
    7. }
    8. class Grass {
    9. (new Animal).walk() //同包下不能访问 proected 修饰的方法
    10. }
    11. }

    5.3、public

    跟 Java 完全一致

    5.4、作用域保护

  • 通过 private[x]或 protected[x]来实现,可以修饰包、类、单例 对象

  • private[x],即为”这个成员除了对[…]中的类或[…]中的包中的 类及它们的伴生对像可见外,对其它所有类都是 private
  • protected[x],即为”这个成员除了对[…]中的类或[…]中的包中 的类及它们的伴生对像可见外,对其它所有类都是 protected

    1. class TestPrivate {
    2. class Student {
    3. private[TestPrivate] def testPrivate1() {
    4. println("in private method");
    5. }
    6. private def testPrivate2() {
    7. println("in private method");
    8. }
    9. def testPublic() {
    10. println("in private method");
    11. }
    12. class Student {
    13. testPrivate1();
    14. }
    15. }
    16. (new Student()).testPrivate1() //有[]作用域修饰,可以访问
    17. (new Student()).testPrivate2() //没有[]作用域修饰,依然是不可以访问
    18. }

    6、运算符

    与Java相似
    没有++,—操作

    7、控制语句

    大部分与Java相似
    差异点:

    1. // for 形式定义
    2. for( var x <- Range ){
    3. statement(s);
    4. }
    5. /*
    6. 以上语法中,Range 可以是一个数字区间表示 i to j ,或者 i
    7. until j。左箭头 <- 用于为变量 x 赋值。
    8. i to j 是一个闭区间
    9. i until j 是一个左闭右开区间
    10. */
    11. // yield的使用
    12. val list = List(1, 2, 3, 4, 5)
    13. var temp: Seq[Int] = for {
    14. str <- list if (str == 1 || str == 2)
    15. } yield str
    16. /*
    17. 注意大括号中用于保存变量和条件,temp 是变量, 循环中的 yield 会把当前的
    18. 元素记下来,保存在集合中,循环结束后将返回该集合。
    19. */
    20. for (x <- temp) {
    21. println(x)
    22. }

    8、方法和函数

    8.1、区别

  • Scala 有方法与函数,二者在语义上的区别很小,在绝大多数情况下,两者是视为对等的

  • Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变 量,即在类中定义的函数即是方法
  • Scala 中的方法跟 Java 的类似,方法是组成类的一部分
  • Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象
  • Scala 中使用 val 语句可以定义函数,def 语句定义方法

    8.2、方法定义

    1. // 定义格式
    2. def functionName ([参数列表]) : [return type] = {
    3. function body
    4. return [expr]
    5. }

    注意:

  • 如果不写等于号和方法主体,则方法会被隐式声明为”抽象 方法”,包含它的类型于是也是一个抽象类型

  • return type 可以是任意合法的 Scala 数据类型,如果 函数没有返回值,可以返回为 Unit,这个类似于 Java 的 void
  • 参数列表中的参数可以使用逗号分隔

    1. // 无返回值函数定义
    2. object TestFunction {
    3. def printMessage() : Unit = {
    4. println("HelloWorld!")
    5. }
    6. }

    8.3、方法调用

  • 当不需要实例化对象时,functionName(参数列表)即可

  • 当需要实实例化对象时,为 instance.functionName(参数 列表)即可

    1. // 不需要实例化对象
    2. object TestFunction {
    3. def printMessage(): Unit = {
    4. println("HelloWorld!")
    5. }
    6. def add4Int(first: Int, second: Int): Int = {
    7. var sum: Int = 0
    8. sum = first + second
    9. return sum
    10. }
    11. def main(args: Array[String]): Unit = {
    12. printMessage();
    13. var sum = add4Int(3, 4);
    14. print("3+4 的和="+sum);
    15. }
    16. }
    17. // 需要实例化对象
    18. object TestFunctionV2 {
    19. class TestClassFunction {
    20. def printMessage(): Unit = {
    21. println("HelloWorld!")
    22. }
    23. def add4Int(first: Int, second: Int): Int = {
    24. var sum: Int = 0
    25. sum = first + second
    26. return sum
    27. }
    28. }
    29. def main(args: Array[String]): Unit = {
    30. var classFunctionInstance = new TestClassFunction;
    31. var sum = classFunctionInstance.add4Int(3, 4);
    32. println("class 3+4 的和=" + sum);
    33. }
    34. }

    9、闭包

  • 闭包是个函数

  • 函数计算的过程,依赖于声明在函数外部的一个或多个变量

    1. object TestCloseFunction {
    2. var factor = 1000
    3. def salaryMoney(i: Int): Int = {
    4. return i * factor
    5. }
    6. def main(args: Array[String]) {
    7. println("月薪 salaryMoney(8) value = " + salaryMoney(8))
    8. println("月薪 salaryMoney(10) value = " + salaryMoney(10))
    9. TestCloseFunction.factor = 10000;
    10. println("年薪 salaryMoney(8) value = " + salaryMoney(8))
    11. println("年薪 salaryMoney(10) value = " + salaryMoney(10))
    12. }
    13. }

    10、字符串

  • 在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类

  • 完全与 java.lang.String 对等

    11、数组

    11.2、概念

  • 用来存储固定大小的同类型元素

  • 元素是通过索引来访问的,第一个元素索引为 0,最后一个元素 的索引为元素总数减 1
  • 与Java相似

差异点:

  • 调用方式
  • 二维数组创建方式
  • 数组合并
    • concat(数组1, 数组2)
  • 创建区间数组

    • range(1, 5, 2)
    • 从1到5,步长为2的数组

      12、函数高级应用

      12.1、函数传名调用

  • 传值调用:先计算参数表达式的值,再应用到函数内部, 把=>去掉即可,即按原始的方式

  • 传名调用:将未计算的参数表达式直接应用到函数内部, 用=>来设置传名调用

    1. //传值
    2. object TestCallByValue {
    3. def main(args: Array[String]) {
    4. delayedCalculator(transmitMe());
    5. }
    6. def transmitMe(): String = {
    7. println("我在 transmitMe 方法中!")
    8. return "transmitMe 返回值";
    9. }
    10. def delayedCalculator(t: String): Unit = {
    11. println("在 delayedCalculator 方法--开始")
    12. println("正式调用传过来的函数: " + t)
    13. println("在 delayedCalculator 方法--结束")
    14. }
    15. }
    16. //传名
    17. object TestCallByName {
    18. def main(args: Array[String]) {
    19. delayedCalculator(transmitMe());
    20. }
    21. def transmitMe(): String = {
    22. println("我在 transmitMe 方法中!")
    23. return "transmitMe 返回值";
    24. }
    25. def delayedCalculator(t: => String): Unit = {
    26. println("在 delayedCalculator 方法--开始")
    27. println("正式调用传过来的函数: " + t)
    28. println("在 delayedCalculator 方法--结束")
    29. }
    30. }

    12.2 、指定参数名调用

    不按照参数顺序调用,直接指定参数

    1. object TestCallByParaName {
    2. def main(args: Array[String]) {
    3. printBabyNames(second = "张二", first = "张一");
    4. }
    5. def printBabyNames(first: String, second: String): Unit
    6. = {
    7. println("第一个孩子叫=" + first);
    8. println("第二个孩子叫=" + second);
    9. }
    10. }

    12.3、可变参数调用

    可传入任意个参数

    1. object TestNonFixParas {
    2. def main(args: Array[String]) {
    3. printAllParasValue("one", "two", "three", "four");
    4. }
    5. def printAllParasValue(paras: String*): Unit = {
    6. for (temp <- paras) {
    7. println(temp);
    8. }
    9. }

    12.4、默认参数值函数

    1. object TestDefaultParaFunction {
    2. def main(args: Array[String]) {
    3. println("完全使用默认值的返回值 : " + salaryMoney());
    4. println("部分使用默认值的返回值 : " + salaryMoney(10));
    5. println("部分使用默认值的返回值 : " + salaryMoney(10,10000));
    6. }
    7. def salaryMoney(a: Int = 5, unit: Int = 1000): Int = {
    8. return a * unit
    9. }
    10. }

    12.5、递归参数

    与Java一致

    12.6、高阶函数

  • 第一种:将一个函数当做另外一个函数的参数,即参数为 函数的函数

    1. object TestHighFunctionByTransmitFunctionPara {
    2. def main(args: Array[String]) {
    3. delayedCalculator(transmitMe());
    4. }
    5. def transmitMe(): String = {
    6. println("我在 transmitMe 方法中!")
    7. return "transmitMe 返回值";
    8. }
    9. def delayedCalculator(t: => String): Unit = {
    10. println("在 delayedCalculator 方法--开始")
    11. println("正式调用传过来的函数: " + t)
    12. println("在 delayedCalculator 方法--结束")
    13. }
    14. }
  • 第二种:返回值是函数的函数,即高阶函数可以产生函数

    1. object TestHighFunctionByRetFunction {
    2. def main(args: Array[String]) {
    3. var mySalaryFun=multiplyBy(1000);
    4. println(mySalaryFun(10));
    5. }
    6. def multiplyBy(salaryUnit:Int)=(x:Int)=>salaryUnit*x
    7. }

    12.7、内嵌函数

    函数内定义函数,定义在函数内的函数称之为局部函数, 亦称内嵌函数

    1. object TestEmbedFunction {
    2. def main(args: Array[String]) {
    3. var msg="HelloWorld";
    4. printMessage(msg);
    5. }
    6. def printMessage(msg: String): Unit = {
    7. def printMessageInner(msg: String): Unit = {
    8. println(msg);
    9. }
    10. printMessageInner(msg);
    11. }
    12. }

    12.8、匿名函数

  • 没有函数名称的函数

  • 使代码更简洁,用=>来表示,左侧是参数列表,右侧是函 数体
    1. // 匿名函数定义:
    2. var inc = (x:Int) => x+1
    3. // 函数使用:
    4. var x = inc(8)+1
    5. // 正常定义:
    6. def incFunction(x: Int): Int = {
    7. return x + 1;
    8. }
    9. // 函数使用:
    10. var x=incFunction(8)+1

12.9、偏应用函数

  • 不需要提供函数需要的所有参数,只需要提供部分,或不 提供所需参数
  • 实现方法:绑定函数的一部分参数,非绑定部分用”_”代 替,从而形成偏应用函数去使用

    1. //传统方法实现(向某人问好)
    2. import java.util.Date
    3. object TestPartialParasFunction {
    4. def main(args: Array[String]) {
    5. val name="张三"
    6. sayHello(name, "上午好")
    7. Thread.sleep(1000)
    8. sayHello(name, "中午好")
    9. Thread.sleep(1000)
    10. sayHello(name, "晚上好")
    11. }
    12. def sayHello(name: String, message: String)
    13. = {
    14. println(name + "----" + message)
    15. }
    16. }
    17. //偏应用函数实现(向某人问好)
    18. def main(args: Array[String]) {
    19. val name="张三"
    20. val partialSay=sayHello(name,_:String);
    21. partialSay("上午好")
    22. Thread.sleep(1000)
    23. partialSay("中午好")
    24. Thread.sleep(1000)
    25. partialSay("晚上好")
    26. }
    27. def sayHello(name: String, message: String) = {
    28. println(name + "----" + message)
    29. }

    12.10、函数柯里化


  • 将原来接受两个参数的函数变成新的接受一个参数的函数 的过程。新的函数返回一个以原有第二个参数为参数的函 数
  • 提高了使用方法的灵活性

    1. object TestCurryingFunction {
    2. def main(args: Array[String]) {
    3. //对应柯里化形式 1 的使用
    4. var curryingAdd1 = add1(3)
    5. //对应柯里化形式 2 的使用
    6. var curryingAdd2 = add2(3)(_)
    7. println(curryingAdd1(4));
    8. println(curryingAdd1(4));
    9. }
    10. //柯里化形式 1
    11. def add1(x: Int) = (y: Int) => x + y;
    12. //柯里化形式 2
    13. def add2(x: Int)(y: Int) = x + y;
    14. }

    13、集合collection

  • 该集合与 Java 中的集合类似,只是 scala 重新实现了自身的集合 抽象

  • 分为可变集合和不可变集合
  • 常用集合列表 | 集合类 | 说明 | | —- | —- | | Scala List(列表) | 元素以线性方式存储,集合中可以存放重复对象。 | | Scala Set(集合) | 集合中的对象不按特定的方式排序,并且没有重复对 象。 | | Scala Map(映射) | KV 对存储 | | Scala 元组 | 元组是不同类型的值的集合 | | Scala Option | 表示有可能包含值的容器,也可能不包含值。 | | Scala Iterator 迭代器 | 迭代器不是一个容器,更确切的说是逐一访问容器内元 素的方法 |

13.1、List

  • 类似于数组,要求所有元素的类型都相同,通过范型来约束
  • 列表是不可变集合,一旦定义了就不能改变
  • 列表具有递归定义的性质,可以嵌套定义,这是与数组 最大的不一样
    1. //List初始化
    2. //第一种
    3. val language: List[String] = List("java","python", "c++")
    4. //第二种
    5. val language= "java" :: ("python" :: ("c++" :: Nil))
    ```scala //常用操作 object TestListFunction { def main(args: Array[String]) { val language1 = “java” :: (“python” :: (“c++” :: Nil)) val nums = Nil /**
  • 基本操作 / println(“基本操作————“); println(“第一语言是 : “ + language1.head) println(“除第 1 个语言之外的其它语言是 : “ + language1.tail) println(“查看列表 site 是否为空 : “ + language1.isEmpty) println(“查看 nums 是否为空 : “ + nums.isEmpty) /*
  • 列表连接 / println(“列表连接————“); val language2 = “c” :: (“php” :: (“go” :: Nil)) // 使用 ::: 运算符 var mainLanguages = language1 ::: language2 println(“language1 ::: language2 : “ + mainLanguages) // 使用 List.:::() 方法 mainLanguages = language1.:::(language2) println(“language1.:::(language2) : “ + mainLanguages) // 使用 concat 方法 mainLanguages = List.concat(language1, language2) println(“List.concat(language1, language2) : “ + mainLanguages) /*
  • fill 填充列表的重复元素 / println(“List fill————“); val bestLanguage = List.fill(3)(“php”) // 重复 Runoob 3 次 println(“bestLanguage : “ + bestLanguage) val num = List.fill(10)(“php”) // 重复元素 “php”, 10 次 println(“num : “ + num) /*
  • List tabulate 通过给定的函数来创建列表 / println(“List tabulate————“); // 通过给定的函数创建 6 个元素 val squares = List.tabulate(6)(n => n n) println(“一维 : “ + squares) // 创建二维列表 val mul = List.tabulate(4, 5)( * ) println(“多维 : “ + mul) /**
  • List.reverse 用于将列表的顺序反转 */ println(“List.reverse————“); println(mainLanguages.reverse); } } ```

    13.2、Set

  • 没有重复的对象集合,所有的元素都是唯一的
  • Set 集合分为可变的和不可变的集合
  • 默认使用不可变集合,完整类路径为: scala.collection.immutable.Set
  • 若要引用可变集合类型,则类路径为: scala.collection.mutable.Set ```scala def main(args: Array[String]): Unit = { val languageSet1 = Set(“java”, “python”, “c++”) val numSet: Set[Int] = Set() /**
  • 基本操作 / println(“基本操作————“); println(“第一语言是 : “ + languageSet1.head) println(“除第 1 个语言之外的其它语言是 : “ + languageSet1.tail) println(“查看列表 site 是否为空 : “ + languageSet1.isEmpty) println(“查看 nums 是否为空 : “ + numSet.isEmpty) /*
  • 集合连接操作 / println(“集合连接————“); val languageSet2 = Set(“c”, “php”, “go”) // ++ 作为运算符使用 var mainlanguageSet = languageSet1 ++ languageSet2 println(“languageSet1 ++ languageSet2 : “ + mainlanguageSet) // ++ 作为方法使用 mainlanguageSet = languageSet1.++(languageSet2) println(“languageSet1.++(languageSet2) : “ + mainlanguageSet) /*
  • 求集合最大、最小元素 / println(“求集合最大和最小元素————“); println(“mainlanguageSet 集合中的最小元素是 : “ + mainlanguageSet.min) println(“mainlanguageSet 集合中的最大元素是 : “ + mainlanguageSet.max) /*
  • 求交集 */ println(“求集合的交集————“) var secondLanguageSet=Set(“shell”,”perl”,”java”) println(“mainlanguageSet.&(secondLanguageSet) : “ + mainlanguageSet.&(secondLanguageSet)) println(“mainlanguageSet.intersect(secondLanguageSet) : “ + mainlanguageSet.intersect(secondLanguageSet)) } ```

    13.3、Map

  • 一种可迭代的键值对(key/value)结构,也称为哈希表
  • 所有的值都可以通过键来获取,键值是唯一的
  • 两种类型,可变与不可变,区别在于可变对象可以修改 它,而不可变对象不可以
  • 默认使用的不可变 Map,可变的 Map 需要使用 import scala.collection.mutable.Map 类
    1. def main(args: Array[String]): Unit = {
    2. // 不可变空 Map,键为字符串,值为整型
    3. var personMap: Map[String, String] = Map()
    4. // 不可变初始化
    5. val languageMap = Map("java" -> "java 程序设计",
    6. "python" -> "python 程序设计", "c++" -> "c++程序设计")
    7. //动态向不可变 map 中添加值
    8. personMap += ("001" -> "张三")
    9. //languageMap += ("java" -> "已经理新了") //此处会报错
    10. println(personMap)
    11. println(languageMap)
    12. //初始化可变 Map
    13. val languageMap2 = scala.collection.mutable.Map("java"
    14. -> "java 程序设计", "python" -> "python 程序设计", "c++" ->
    15. "c++程序设计")
    16. //向可变 Map 中添加值
    17. languageMap2.put("python","已经更新了")
    18. println(languageMap2)
    19. }
    ```scala def main(args: Array[String]): Unit = { // 不可变空 Map,键为字符串,值为整型 var personMap: Map[String, String] = Map() // 不可变初始化 val languageMap = Map(“java” -> “java 程序设计”, “python” -> “python 程序设计”, “c++” -> “c++程序设计”) /**
  • 基础操作 / println(“基础操作————-“) println(“languageMap 中的键为 : “ + languageMap.keys) println(“languageMap 中的值为 : “ + languageMap.values) println(“检测 languageMap 是否为空:” + languageMap.isEmpty) println(“检测 personMap 是否为空: “ + personMap.isEmpty) /*
  • map 合并 / println(“ map 合并————-“) val languageMap2 = Map(“C” -> “C 程序设计”) // ++ 作为运算符 var mainLanguages = languageMap ++ languageMap2 println(“languageMap ++ languageMap2 : “ + mainLanguages) // ++ 作为方法 mainLanguages = languageMap.++(languageMap2) println(“languageMap.++(languageMap2)) : “ + mainLanguages) /*
  • map 的 keys 和 values 输出 / println(“map 的 keys 和 values 输出————-“) mainLanguages.keys.foreach { i => print(“Key = “ + i) println(“ Value = “ + mainLanguages(i)) } /*
  • 查看 Map 中是否存在指定的 Key */ println(“查看 Map 中是否存在指定的 Key————-“) if (mainLanguages.contains(“java”)) { println(“java 键存在,对应的值为 :” + mainLanguages(“java”)) } else { println(“java 键不存在”) } if (mainLanguages.contains(“c#”)) { println(“java 键存在,对应的值为 :” + mainLanguages(“c#”)) } else { println(“c#键不存在”) } } ```

    13.4、元组

  • 与列表相似,元组是不可变的
  • 与列表不同的是,元组可以包含不同类型的元素
  • 元组是通过”()”来定义的
    ```scala def main(args: Array[String]): Unit = { //直接定义元组 var personInfo = (“s0001”, “张三”, 21, “河北科技大学”, 1.80) //通过 TupleN 来定义,N 可以是 1 至 22 个可选的元组个数 var pessonInfoTuple5 = new Tuple5(“s0001”, “张三”, 21, “河北科技大学”, 1.80); /**
  • 元组访问,通过元组的索引下标访问,从 1 开始,元组对象._1 代表第 1 个元素, 元组对象._2 代表第 2 个元素, / println(“元组访问————-“); println(“学号=” + personInfo._1); println(“姓名=” + personInfo._2); println(“年龄=” + personInfo._3); println(“学校=” + personInfo._4); println(“身高=” + personInfo._5); /*
  • 元组遍历 / println(“元组遍历————-“); personInfo.productIterator.foreach { i => println(“元素值 = “ + i) } /*
  • 元组转换成字符串 */ println(“元组转换成字符串 ————-“); println(personInfo.toString()) } ```

    13.5、Option[T]

  • 表示有可能包含值的容器,也可能不包含值。主要用来表 示一个值是可选的
  • Option[T] 是一个类型为 T 的可选值的容器: 如果值存 在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None
    1. def main(args: Array[String]): Unit = {
    2. //定义一个 map 对象
    3. val mainLanguagesMap = Map("java" -> "java 程序设计",
    4. "python" -> "python 程序设计")
    5. //通过指定键值,获取可能的 value,其返回值是一个
    6. Option[T],代表有可能会存在该键值对应的 value,也有可能不存在
    7. var javaDesc: Option[String] =
    8. mainLanguagesMap.get("java");
    9. var phpDesc: Option[String] =
    10. mainLanguagesMap.get("php");
    11. //打印拿到的结果
    12. println("mainLanguagesMap.get(\"java\") : " +
    13. javaDesc)
    14. println("mainLanguagesMap.get(\"php\") : " +
    15. phpDesc)
    16. //判断结果是否有值,即是否为 None
    17. println("javaDesc.isEmpty: " + javaDesc.isEmpty)
    18. println("phpDesc.isEmpty: " + phpDesc.isEmpty)
    19. //对拿到的结果做 getOrElse 操作,即如果不存在该 key,则取
    20. 方法的默认值
    21. println("mainLanguagesMap.get(\"java\") : " +
    22. javaDesc.getOrElse("没有拿到 java 的描述信息"))
    23. println("mainLanguagesMap.get(\"php\") : " +
    24. phpDesc.getOrElse("没有拿到 php 的描述信息"))
    25. }

13.6、Iterator(迭代器)

  • 不是一个集合,它是一种用于访问集合的方法
  • 基本操作是 hasNext 和 next
    ```scala def main(args: Array[String]): Unit = { val it1 = Iterator(“java”, “python”, “c++”) val it2 = Iterator(“java”, “python”, “c++”) val it3 = Iterator(“java”, “python”, “c++”) val it4 = Iterator(“java”, “python”, “c++”) val it5 = Iterator(“java”, “python”, “c++”) /**
  • 迭代器遍历集合 / println(“遍历集合————-“); while (it1.hasNext) { println(it1.next()) } /*
  • 迭代器求集合的最大值 / println(“求迭代器集合的最大值————-“); println(it2.max) /*
  • 迭代器求集合的最小值 / println(“求迭代器集合的最小值————-“); println(it3.min) /*
  • 迭代器求集合的长度 */ println(“迭代器求集合的长度————-“); println(it4.size) println(it5.length) } ```

    14、类和对象

  • Java中类和对象
    • 类是对象的抽象,而对象是类的具体实例
    • 类是抽象的,不占用内存,而对象是具体的,占用存储空 间
    • 类是用于创建对象的模板,它定义包括在特定类型的对象 中的方法和变量
  • Scala中类和对象
    • 一个 Scala 源文件中可以有多个类
    • 类访问修饰符默认均是 public 的,并不需要声明
    • 通过 new 来实例化类,生成相应的对象
    • 类本身是不能作为程序主入口的,必须通过定义 Object 对 象,该对象的 main 方法作为程序的主入口 ```scala /**
  • 主构造方法传参,共三个参数,分别为姓名、性别、年龄 / class Person(oneName: String, oneGender: String, oneAge: Int) { //将构造方法传入的局部变量,传递成类的成员变量,方便后续在外部使用使用 var name: String = oneName var gender: String = oneGender var age: Int = oneAge //定义成员方法 def makeMoney(method: String) { println(“makeMoney method=” + method); } } /*
  • 定义一个对象作为程序的运行主类,其 main 方法作为程序运行的主入口 */ object TestPerson { def main(args: Array[String]): Unit = { //通过 new 实例化 Person 类的一个对象 person var person = new Person(“张一”, “male”, 20) //通过对象.属性的方式,获取对象的属性值 println(“person.name=” + person.name) println(“person.gender=” + person.gender) println(“person.age=” + person.age) //通过对象.方法名(参数)的方式,调用方法 person.makeMoney(“coding”) } } ```

    14.1、类继承

  • Scala 继承一个基类跟 Java 很相似,但有若干不同之处
  • 重写一个非抽象方法必须使用 override 修饰符
  • 只有主构造函数才可以往基类的构造函数里写参数
  • 在子类中重写超类的抽象方法时,你不需要使用 override 关键字
    ```scala /**
  • 主构造方法传参,共三个参数,分别为姓名、性别、年龄 / class Person(oneName: String, oneGender: String, oneAge: Int) { //将构造方法传入的局部变量,传递成类的成员变量,方便后续在外部使用使用 var name: String = oneName var gender: String = oneGender var age: Int = oneAge //定义成员方法 def makeMoney(method: String) { println(“makeMoney method=” + method); } } /*
  • Student 类继承 Person 类,将相关属性直接传递给父类构造方法 / class Student(oneStdNo: String, oneName: String, oneGender: String, oneAge: Int) extends Person(oneName, oneGender, oneAge) { //将新增加构造方法的参数值赋给的成员属性,方便后续在外部使用 var stdNo = oneStdNo; //重写父类的非抽象成员方法,必须填加 override 关键字 override def makeMoney(method: String) { println(“我是个学生,我的学号是” + this.stdNo + “,makeMoney method=” + method); } } /*
  • 定义一个对象作为程序的运行主类,其 main 方法作为程序运行的主入口 */ object TestPerson { def main(args: Array[String]): Unit = { //通过 new 实例化 Person 类的一个对象 person var person = new Student(“s0001”, “张一”, “male”, 20) //通过对象.属性的方式,获取对象的属性值 println(“person.stdno=” + person.stdNo) println(“person.name=” + person.name) println(“person.gender=” + person.gender) println(“person.age=” + person.age) //通过对象.方法名(参数)的方式,调用方法 person.makeMoney(“coding”) } } ```

    14.2、单例模式

  • static 在 scala 中是没有的,不符合纯面向对象的模型
  • scala 中使用 object 关键字来解决单例模式问题。object 与类的区别是 object 不能够带参数
  • 伴生对象:除了定义的类之外,还要定义一个同名的 object 对象,当单例对象与某个类共享同一个名称时,他 被称作是这个类的伴生对象:companion object
  • 伴生类:该伴生对象对应的类,即为伴生类 companion class
  • 必须在同一个源文件里定义类和它的伴生对象
  • 类和它的伴生对象可以互相访问其私有成员
    ```scala public class SingletonPattern { public static void main(String[] args) {
    1. Person.lazy().accumulation();
    2. Person.lazy().accumulation();
    3. Person1.hungry().accumulation();
    4. Person1.hungry().accumulation();
    } }

/**

  • 懒汉模式 */ class Person { private Person() { }

    private Integer num = 0; public void accumulation() {

    1. System.out.println(num++);

    } static Person person = null; public static Person lazy() {

    1. if (person == null) {
    2. person = new Person();
    3. }
    4. return person;

    } }

/**

  • 饿汉模式 */ class Person1 { private Person1() { }

    private Integer num = 0; public void accumulation() {

    1. System.out.println(num++);

    } static Person1 person = new Person1(); public static Person1 hungry() {

    1. return person;

    } } ```

    15、特质 trait

  • 相当于 Java 的接口和抽象类的二合一,即可以当接口使用,也可 以像抽象类去定义实际的方法和抽象方法去使用
  • 特征是支持多继承的,解决了 scala 单继承的问题,间接达到 scala 多继承的效果
  • 用关键字 trait 来定义特征 ```scala /**
  • 定义核心计算特征 / trait CalcuteCoreTrait { def add(a: Int, b: Int): Int = a + b def minus(a: Int, b: Int): Int = a - b def factorial(n: Int): Int } class TLCalculator(oneName: String) extends CalcuteCoreTrait { var name = oneName def factorial(n: Int): Int = { if (n <= 1) { return 1 } else { return n factorial(n - 1) } } } object TestTrait { def main(args: Array[String]): Unit = { var tl:CalcuteCoreTrait=new TLCalculator(“晨光计 算器”) var a=3 var b=4 println(“a+b=”+tl.add(a, b)) println(“a-b=”+tl.minus(a, b)) println(“b!=”+tl.factorial(b)) } } ```

    16、模式匹配

    类比于 java 中的 switch…case,但比其要强大、灵活很多
    旨在解决符合一定模式(值也是模式的一种)情况下的匹配与处 理问题
  • 一个模式匹配包含了一系列备选项,每个都开始于关键字 case。 每个备选项都包含了一个模式及一到多个表达式。箭头符号=>隔开了模式和表达式
  • 选择器 match {备选项},match 表达式通过以代码编写的先后次 序尝试每个模式来完成计算,只要发现有一个匹配的 case,剩下 的 case 不会继续匹配

    1. def main(args: Array[String]) {
    2. println(selfMatch("one"))
    3. println(selfMatch(2))
    4. println(selfMatch("III"))
    5. println(selfMatch("five"))
    6. }
    7. def selfMatch(x: Any): Any = x match {
    8. case "one" => 1
    9. case 2 => "two"
    10. case "III" => "希腊数字 3"
    11. case _ => "其它不认识了"
    12. }

    17、正则表达式

    与 Java 当中的正则表达式的作用完全相同
    用””.r 或是 scala.util.matching 包中的 Regex 类实现对正 则的支持抽象

    1. def main(args: Array[String]) {
    2. //定义一个字符串作为正则表达式
    3. val pattern = "十八大".r
    4. //正则要去匹配的源字符串
    5. val str = "十八大是一个重要具有里程碑式的会议!"
    6. //在源串中查找第一个匹配 pattern 正则表达式的值
    7. println(pattern findFirstIn str)
    8. }
    1. /*
    2. findAllIn:查找所有匹配结果
    3. mkString:连接正则表达式匹配结果的字符串
    4. 正则可以使用管道(|)来设置不同的模式
    5. */
    6. def main(args: Array[String]) {
    7. //定义一个字符串作为正则表达式
    8. val pattern = new Regex("(十八|18)大")
    9. //正则要去匹配的源字符串
    10. val str = "十八大是一个重要具有里程碑式的会议,18 大以
    11. 来社会各届取得了显著的进展和成果!"
    12. //在源串中查找所有匹配 pattern 正则表达式的值
    13. println((pattern findAllIn str).mkString(","))
    14. }

    18、异常处理

  • 异常处理机制与 Java 语言相似,其异常类也采用了 Java 类,并 没有重写

  • 主要包括异常抛出和异常捕获两大方面
  • 抛出异常用 throw,声明可能的异常与 Java 不同,采用的注解式的@throws(classOf[SomeException])
  • 捕获异常,采用的 try…catch 的模式匹配的形式
  • Scala 里不需要捕获检查异常:checked exception,也不是必须 把它们声明在 throws 子句中。 可以用@throws 标注声明一个 throws 子句,但这不是必需的 该机制最大的问题是如果遇到异常没有补捉,则程序会终止,如 果进行了捕捉,可以按照程序设定的方式去进行,而不必须停止
    1. // 方法内抛出异常
    2. def main(args: Array[String]) {
    3. throw new Exception("测试异常抛出!");
    4. }
    5. // 方法定义时声明要抛出异常
    6. object TestException {
    7. def main(args: Array[String]) {
    8. callMe()
    9. }
    10. @throws(classOf[Exception])
    11. def callMe() = {
    12. println("i am in callMe method")
    13. }
    14. }
    15. // 捕获异常
    16. def main(args: Array[String]) {
    17. try {
    18. val f = new FileReader("input.txt")
    19. } catch {
    20. case ex: FileNotFoundException => {
    21. println("不好意思,文件没有找到!")
    22. }
    23. case ex: IOException => {
    24. println("不明原因的 IO 异常!")
    25. }
    26. }
    27. }
    28. // 捕获异常时候-加入 finally 收尾
    29. def main(args: Array[String]) {
    30. try {
    31. val f = new FileReader("input.txt")
    32. } catch {
    33. case ex: FileNotFoundException => {
    34. println("不好意思,文件没有找到!")
    35. }
    36. case ex: IOException => {
    37. println("不明原因的 IO 异常!")
    38. }
    39. } finally {
    40. println("无论 try...catch 如何,都会执行 finally,我在
    41. finally 中!")
    42. }
    43. }

19、提取器(Extractor)

  • 提取器是从传递给它的对象中提取出构造该对象的参数
  • 提取器是一个带有 unapply 方法的对象。unapply 方法算是 apply 方法的反向操作:unapply 接受一个对象,然后从对象中提取 值,提取的值通常是用来构造该对象的值
  • apply 与 unapply 方法是互反的,apply 用于构造一个对象,而不 需要用 new 方法是其重要特点,unapply 是反向解开这个对象, 将其对应的参数值提取出来

    1. object TestUnapplyPatternMatch {
    2. def main(args: Array[String]) {
    3. //自动调用 TestUnapplyPatternMatch 的 apply 方法
    4. val loginInfo = TestUnapplyPatternMatch("tianliang", "192.168.1.33")
    5. println(loginInfo)
    6. loginInfo match {
    7. //unapply 被自动调用
    8. case TestUnapplyPatternMatch(username, ip) => println(username + "
    9. 登陆了" + ip + " 这台机器!")
    10. case _ => println(loginInfo)
    11. }
    12. }
    13. def apply(username: String, ip: String) = username + "@" + ip
    14. def unapply(loginInfo: String): Option[(String, String)] = {
    15. val parts = loginInfo split "@"
    16. if (parts.length == 2) {
    17. Some(parts(0), parts(1))
    18. } else {
    19. None
    20. }
    21. }
    22. }

    20、文件I\O

  • 与 Java 基本类似

  • 其文件写操作,直接用的都是 java 中 的 I/O 类
  • 增加了少部分新 IO 类,并对 API 中做了部分简化 ```scala // 从文件中读取内容 def main(args: Array[String]) { println(“读取文件内容为:”) println(“第一种方式————-“) var fileSource = Source.fromFile(“output.txt”, “utf8”) for (line <- fileSource.getLines) { println(line) } println(“第二种方式————-“) Source.fromFile(“output.txt”, “utf-8”).foreach { print _ } println(“第三种方式————-“) fileSource = Source.fromFile(“output.txt”, “utf-8”) fileSource.foreach(print) }

```