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 等属于动态语言。
- 扩展性
- 提供了许多独特的语言机制,可以以库的形式轻易无缝添 加新的语言结构。
- 并发性
- 下载地址: https://www.scala-lang.org/download/all.html
- 双击安装
- 打开idea
- 下载插件Scala
- 创建Scala项目
1.6、应用前景
- 技术方面
- 完全兼容 Java,运行于 JVM 虚拟机之上
- 支持函数式编程和类型推断
- 结合面向过程和面向对象,并保证代码简洁及优雅
- 开发工具 IDE 非常成熟
应用方面
对象:类的一个具体实例,对象包含属性和方法,如旺财有属性 毛色和看家本领能力
- 类:类是对象的抽象,对象是类的一个实例
- 方法:描述类所拥有的行为能力,一个类可以拥有多个方法
属性:也称字段,即每个对象拥有它自身实例变量集合,通过赋 值来创建真正的属性值
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、关键字和注释
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 个值类型
整型字面量:如:0,1,0xff,07L
- 浮点型字面量:0.0,3.14159f
- 布尔型字面量:true 或者 false
- 字符字面量:单引号括起来,如’a’,’b’,’\t’
- 字符串字面量:双引号括起来,如”HelloWorld”,”MyName”
-
4、变量
4.1、常量
在程序运行过程中其值不会发生变化的量叫做常量。如:”A”、 “B”、”123”太丰富
使用 val 来声明常量val constString:String="hero";constString="new_hero";
4.2、变量
在程序运行过程中其值可能发生改变的量叫做变量。如:对象的 名称、年龄、发色、身材等
使用 var 来声明变量var varString:String="name";varString="new_name";
4.3、变量声明
显式声明类型
var variableName : DataType [= Initial Value]或val constName: DataType [= Initial Value]
隐式声明类型
var myString="HelloWorld";var myInt=1;
批量变量声明
var a,b=10;println(a+b);
5、访问修饰符
scala 访问修饰符包括 private,protected,public,对象的访问级别默认都是 public
5.1、private
仅在包含了成员定义的类或对象内部可见
在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员
class TestPrivate {class Person {private def testPrivate() {println("in private method");}def testPublic() {println("in private method");}class Student {testPrivate(); //正确}(new Person()).testPublic() //public 方法访问,正确(new Person()).testPrivate() //private 方法访问,错误}
5.2、protected
比 java 的 protected 更严格,除了子类可以访问,同包下的类是不能访问的
class TestProtected {class Animal {protected def walk() { println("i can walk!") }}class Person extends Animal {walk() //子父类继承的情况下,能访问 proected 修饰的方法}class Grass {(new Animal).walk() //同包下不能访问 proected 修饰的方法}}
5.3、public
5.4、作用域保护
通过 private[x]或 protected[x]来实现,可以修饰包、类、单例 对象
- private[x],即为”这个成员除了对[…]中的类或[…]中的包中的 类及它们的伴生对像可见外,对其它所有类都是 private
protected[x],即为”这个成员除了对[…]中的类或[…]中的包中 的类及它们的伴生对像可见外,对其它所有类都是 protected
class TestPrivate {class Student {private[TestPrivate] def testPrivate1() {println("in private method");}private def testPrivate2() {println("in private method");}def testPublic() {println("in private method");}class Student {testPrivate1();}}(new Student()).testPrivate1() //有[]作用域修饰,可以访问(new Student()).testPrivate2() //没有[]作用域修饰,依然是不可以访问}
6、运算符
7、控制语句
大部分与Java相似
差异点:// for 形式定义for( var x <- Range ){statement(s);}/*以上语法中,Range 可以是一个数字区间表示 i to j ,或者 iuntil j。左箭头 <- 用于为变量 x 赋值。i to j 是一个闭区间i until j 是一个左闭右开区间*/// yield的使用val list = List(1, 2, 3, 4, 5)var temp: Seq[Int] = for {str <- list if (str == 1 || str == 2)} yield str/*注意大括号中用于保存变量和条件,temp 是变量, 循环中的 yield 会把当前的元素记下来,保存在集合中,循环结束后将返回该集合。*/for (x <- temp) {println(x)}
8、方法和函数
8.1、区别
Scala 有方法与函数,二者在语义上的区别很小,在绝大多数情况下,两者是视为对等的
- Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变 量,即在类中定义的函数即是方法
- Scala 中的方法跟 Java 的类似,方法是组成类的一部分
- Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象
Scala 中使用 val 语句可以定义函数,def 语句定义方法
8.2、方法定义
// 定义格式def functionName ([参数列表]) : [return type] = {function bodyreturn [expr]}
注意:
如果不写等于号和方法主体,则方法会被隐式声明为”抽象 方法”,包含它的类型于是也是一个抽象类型
- return type 可以是任意合法的 Scala 数据类型,如果 函数没有返回值,可以返回为 Unit,这个类似于 Java 的 void
参数列表中的参数可以使用逗号分隔
// 无返回值函数定义object TestFunction {def printMessage() : Unit = {println("HelloWorld!")}}
8.3、方法调用
当不需要实例化对象时,functionName(参数列表)即可
当需要实实例化对象时,为 instance.functionName(参数 列表)即可
// 不需要实例化对象object TestFunction {def printMessage(): Unit = {println("HelloWorld!")}def add4Int(first: Int, second: Int): Int = {var sum: Int = 0sum = first + secondreturn sum}def main(args: Array[String]): Unit = {printMessage();var sum = add4Int(3, 4);print("3+4 的和="+sum);}}// 需要实例化对象object TestFunctionV2 {class TestClassFunction {def printMessage(): Unit = {println("HelloWorld!")}def add4Int(first: Int, second: Int): Int = {var sum: Int = 0sum = first + secondreturn sum}}def main(args: Array[String]): Unit = {var classFunctionInstance = new TestClassFunction;var sum = classFunctionInstance.add4Int(3, 4);println("class 3+4 的和=" + sum);}}
9、闭包
闭包是个函数
函数计算的过程,依赖于声明在函数外部的一个或多个变量
object TestCloseFunction {var factor = 1000def salaryMoney(i: Int): Int = {return i * factor}def main(args: Array[String]) {println("月薪 salaryMoney(8) value = " + salaryMoney(8))println("月薪 salaryMoney(10) value = " + salaryMoney(10))TestCloseFunction.factor = 10000;println("年薪 salaryMoney(8) value = " + salaryMoney(8))println("年薪 salaryMoney(10) value = " + salaryMoney(10))}}
10、字符串
在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类
-
11、数组
11.2、概念
用来存储固定大小的同类型元素
- 元素是通过索引来访问的,第一个元素索引为 0,最后一个元素 的索引为元素总数减 1
- 与Java相似
差异点:
- 调用方式
- 数组名数组类型
- 二维数组创建方式
- ofDimInt
- 数组合并
- concat(数组1, 数组2)
创建区间数组
传值调用:先计算参数表达式的值,再应用到函数内部, 把=>去掉即可,即按原始的方式
传名调用:将未计算的参数表达式直接应用到函数内部, 用=>来设置传名调用
//传值object TestCallByValue {def main(args: Array[String]) {delayedCalculator(transmitMe());}def transmitMe(): String = {println("我在 transmitMe 方法中!")return "transmitMe 返回值";}def delayedCalculator(t: String): Unit = {println("在 delayedCalculator 方法--开始")println("正式调用传过来的函数: " + t)println("在 delayedCalculator 方法--结束")}}//传名object TestCallByName {def main(args: Array[String]) {delayedCalculator(transmitMe());}def transmitMe(): String = {println("我在 transmitMe 方法中!")return "transmitMe 返回值";}def delayedCalculator(t: => String): Unit = {println("在 delayedCalculator 方法--开始")println("正式调用传过来的函数: " + t)println("在 delayedCalculator 方法--结束")}}
12.2 、指定参数名调用
不按照参数顺序调用,直接指定参数
object TestCallByParaName {def main(args: Array[String]) {printBabyNames(second = "张二", first = "张一");}def printBabyNames(first: String, second: String): Unit= {println("第一个孩子叫=" + first);println("第二个孩子叫=" + second);}}
12.3、可变参数调用
可传入任意个参数
object TestNonFixParas {def main(args: Array[String]) {printAllParasValue("one", "two", "three", "four");}def printAllParasValue(paras: String*): Unit = {for (temp <- paras) {println(temp);}}
12.4、默认参数值函数
object TestDefaultParaFunction {def main(args: Array[String]) {println("完全使用默认值的返回值 : " + salaryMoney());println("部分使用默认值的返回值 : " + salaryMoney(10));println("部分使用默认值的返回值 : " + salaryMoney(10,10000));}def salaryMoney(a: Int = 5, unit: Int = 1000): Int = {return a * unit}}
12.5、递归参数
12.6、高阶函数
第一种:将一个函数当做另外一个函数的参数,即参数为 函数的函数
object TestHighFunctionByTransmitFunctionPara {def main(args: Array[String]) {delayedCalculator(transmitMe());}def transmitMe(): String = {println("我在 transmitMe 方法中!")return "transmitMe 返回值";}def delayedCalculator(t: => String): Unit = {println("在 delayedCalculator 方法--开始")println("正式调用传过来的函数: " + t)println("在 delayedCalculator 方法--结束")}}
第二种:返回值是函数的函数,即高阶函数可以产生函数
object TestHighFunctionByRetFunction {def main(args: Array[String]) {var mySalaryFun=multiplyBy(1000);println(mySalaryFun(10));}def multiplyBy(salaryUnit:Int)=(x:Int)=>salaryUnit*x}
12.7、内嵌函数
函数内定义函数,定义在函数内的函数称之为局部函数, 亦称内嵌函数
object TestEmbedFunction {def main(args: Array[String]) {var msg="HelloWorld";printMessage(msg);}def printMessage(msg: String): Unit = {def printMessageInner(msg: String): Unit = {println(msg);}printMessageInner(msg);}}
12.8、匿名函数
没有函数名称的函数
- 使代码更简洁,用=>来表示,左侧是参数列表,右侧是函 数体
// 匿名函数定义:var inc = (x:Int) => x+1// 函数使用:var x = inc(8)+1// 正常定义:def incFunction(x: Int): Int = {return x + 1;}// 函数使用:var x=incFunction(8)+1
12.9、偏应用函数
- 不需要提供函数需要的所有参数,只需要提供部分,或不 提供所需参数
实现方法:绑定函数的一部分参数,非绑定部分用”_”代 替,从而形成偏应用函数去使用
//传统方法实现(向某人问好)import java.util.Dateobject TestPartialParasFunction {def main(args: Array[String]) {val name="张三"sayHello(name, "上午好")Thread.sleep(1000)sayHello(name, "中午好")Thread.sleep(1000)sayHello(name, "晚上好")}def sayHello(name: String, message: String)= {println(name + "----" + message)}}//偏应用函数实现(向某人问好)def main(args: Array[String]) {val name="张三"val partialSay=sayHello(name,_:String);partialSay("上午好")Thread.sleep(1000)partialSay("中午好")Thread.sleep(1000)partialSay("晚上好")}def sayHello(name: String, message: String) = {println(name + "----" + message)}
12.10、函数柯里化
- 将原来接受两个参数的函数变成新的接受一个参数的函数 的过程。新的函数返回一个以原有第二个参数为参数的函 数
提高了使用方法的灵活性
object TestCurryingFunction {def main(args: Array[String]) {//对应柯里化形式 1 的使用var curryingAdd1 = add1(3)//对应柯里化形式 2 的使用var curryingAdd2 = add2(3)(_)println(curryingAdd1(4));println(curryingAdd1(4));}//柯里化形式 1def add1(x: Int) = (y: Int) => x + y;//柯里化形式 2def add2(x: Int)(y: Int) = x + y;}
13、集合collection
该集合与 Java 中的集合类似,只是 scala 重新实现了自身的集合 抽象
- 分为可变集合和不可变集合
- 常用集合列表 | 集合类 | 说明 | | —- | —- | | Scala List(列表) | 元素以线性方式存储,集合中可以存放重复对象。 | | Scala Set(集合) | 集合中的对象不按特定的方式排序,并且没有重复对 象。 | | Scala Map(映射) | KV 对存储 | | Scala 元组 | 元组是不同类型的值的集合 | | Scala Option | 表示有可能包含值的容器,也可能不包含值。 | | Scala Iterator 迭代器 | 迭代器不是一个容器,更确切的说是逐一访问容器内元 素的方法 |
13.1、List
- 类似于数组,要求所有元素的类型都相同,通过范型来约束
- 列表是不可变集合,一旦定义了就不能改变
- 列表具有递归定义的性质,可以嵌套定义,这是与数组 最大的不一样
```scala //常用操作 object TestListFunction { def main(args: Array[String]) { val language1 = “java” :: (“python” :: (“c++” :: Nil)) val nums = Nil /**//List初始化//第一种val language: List[String] = List("java","python", "c++")//第二种val language= "java" :: ("python" :: ("c++" :: 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 类
```scala def main(args: Array[String]): Unit = { // 不可变空 Map,键为字符串,值为整型 var personMap: Map[String, String] = Map() // 不可变初始化 val languageMap = Map(“java” -> “java 程序设计”, “python” -> “python 程序设计”, “c++” -> “c++程序设计”) /**def main(args: Array[String]): Unit = {// 不可变空 Map,键为字符串,值为整型var personMap: Map[String, String] = Map()// 不可变初始化val languageMap = Map("java" -> "java 程序设计","python" -> "python 程序设计", "c++" -> "c++程序设计")//动态向不可变 map 中添加值personMap += ("001" -> "张三")//languageMap += ("java" -> "已经理新了") //此处会报错println(personMap)println(languageMap)//初始化可变 Mapval languageMap2 = scala.collection.mutable.Map("java"-> "java 程序设计", "python" -> "python 程序设计", "c++" ->"c++程序设计")//向可变 Map 中添加值languageMap2.put("python","已经更新了")println(languageMap2)}
- 基础操作 / 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
def main(args: Array[String]): Unit = {//定义一个 map 对象val mainLanguagesMap = Map("java" -> "java 程序设计","python" -> "python 程序设计")//通过指定键值,获取可能的 value,其返回值是一个Option[T],代表有可能会存在该键值对应的 value,也有可能不存在var javaDesc: Option[String] =mainLanguagesMap.get("java");var phpDesc: Option[String] =mainLanguagesMap.get("php");//打印拿到的结果println("mainLanguagesMap.get(\"java\") : " +javaDesc)println("mainLanguagesMap.get(\"php\") : " +phpDesc)//判断结果是否有值,即是否为 Noneprintln("javaDesc.isEmpty: " + javaDesc.isEmpty)println("phpDesc.isEmpty: " + phpDesc.isEmpty)//对拿到的结果做 getOrElse 操作,即如果不存在该 key,则取方法的默认值println("mainLanguagesMap.get(\"java\") : " +javaDesc.getOrElse("没有拿到 java 的描述信息"))println("mainLanguagesMap.get(\"php\") : " +phpDesc.getOrElse("没有拿到 php 的描述信息"))}
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) {
} }Person.lazy().accumulation();Person.lazy().accumulation();Person1.hungry().accumulation();Person1.hungry().accumulation();
/**
懒汉模式 */ class Person { private Person() { }
private Integer num = 0; public void accumulation() {
System.out.println(num++);
} static Person person = null; public static Person lazy() {
if (person == null) {person = new Person();}return person;
} }
/**
饿汉模式 */ class Person1 { private Person1() { }
private Integer num = 0; public void accumulation() {
System.out.println(num++);
} static Person1 person = new Person1(); public static Person1 hungry() {
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 不会继续匹配
def main(args: Array[String]) {println(selfMatch("one"))println(selfMatch(2))println(selfMatch("III"))println(selfMatch("five"))}def selfMatch(x: Any): Any = x match {case "one" => 1case 2 => "two"case "III" => "希腊数字 3"case _ => "其它不认识了"}
17、正则表达式
与 Java 当中的正则表达式的作用完全相同
用””.r 或是 scala.util.matching 包中的 Regex 类实现对正 则的支持抽象def main(args: Array[String]) {//定义一个字符串作为正则表达式val pattern = "十八大".r//正则要去匹配的源字符串val str = "十八大是一个重要具有里程碑式的会议!"//在源串中查找第一个匹配 pattern 正则表达式的值println(pattern findFirstIn str)}
/*findAllIn:查找所有匹配结果mkString:连接正则表达式匹配结果的字符串正则可以使用管道(|)来设置不同的模式*/def main(args: Array[String]) {//定义一个字符串作为正则表达式val pattern = new Regex("(十八|18)大")//正则要去匹配的源字符串val str = "十八大是一个重要具有里程碑式的会议,18 大以来社会各届取得了显著的进展和成果!"//在源串中查找所有匹配 pattern 正则表达式的值println((pattern findAllIn str).mkString(","))}
18、异常处理
异常处理机制与 Java 语言相似,其异常类也采用了 Java 类,并 没有重写
- 主要包括异常抛出和异常捕获两大方面
- 抛出异常用 throw,声明可能的异常与 Java 不同,采用的注解式的@throws(classOf[SomeException])
- 捕获异常,采用的 try…catch 的模式匹配的形式
- Scala 里不需要捕获检查异常:checked exception,也不是必须 把它们声明在 throws 子句中。 可以用@throws 标注声明一个 throws 子句,但这不是必需的 该机制最大的问题是如果遇到异常没有补捉,则程序会终止,如 果进行了捕捉,可以按照程序设定的方式去进行,而不必须停止
// 方法内抛出异常def main(args: Array[String]) {throw new Exception("测试异常抛出!");}// 方法定义时声明要抛出异常object TestException {def main(args: Array[String]) {callMe()}@throws(classOf[Exception])def callMe() = {println("i am in callMe method")}}// 捕获异常def main(args: Array[String]) {try {val f = new FileReader("input.txt")} catch {case ex: FileNotFoundException => {println("不好意思,文件没有找到!")}case ex: IOException => {println("不明原因的 IO 异常!")}}}// 捕获异常时候-加入 finally 收尾def main(args: Array[String]) {try {val f = new FileReader("input.txt")} catch {case ex: FileNotFoundException => {println("不好意思,文件没有找到!")}case ex: IOException => {println("不明原因的 IO 异常!")}} finally {println("无论 try...catch 如何,都会执行 finally,我在finally 中!")}}
19、提取器(Extractor)
- 提取器是从传递给它的对象中提取出构造该对象的参数
- 提取器是一个带有 unapply 方法的对象。unapply 方法算是 apply 方法的反向操作:unapply 接受一个对象,然后从对象中提取 值,提取的值通常是用来构造该对象的值
apply 与 unapply 方法是互反的,apply 用于构造一个对象,而不 需要用 new 方法是其重要特点,unapply 是反向解开这个对象, 将其对应的参数值提取出来
object TestUnapplyPatternMatch {def main(args: Array[String]) {//自动调用 TestUnapplyPatternMatch 的 apply 方法val loginInfo = TestUnapplyPatternMatch("tianliang", "192.168.1.33")println(loginInfo)loginInfo match {//unapply 被自动调用case TestUnapplyPatternMatch(username, ip) => println(username + "登陆了" + ip + " 这台机器!")case _ => println(loginInfo)}}def apply(username: String, ip: String) = username + "@" + ipdef unapply(loginInfo: String): Option[(String, String)] = {val parts = loginInfo split "@"if (parts.length == 2) {Some(parts(0), parts(1))} else {None}}}
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) }
```
