![7b773f3b4f1ddc678121914da821dc46.png](https://img-blog.csdnimg.cn/img_convert/7b773f3b4f1ddc678121914da821dc46.png)
一、变量和数据类型
注释
// 单行注释
/*
多行注释
*/
/**
* doc注释
*/
变量
变量的定义:
var | val 变量名 :变量类型 = 变量值
var 可变类型
var name :String = "zhangsan"
val 不可变类型
val sex :String = "mile"
注意:
- 变量的类型如果能够通过变量值推断出来,那么可以省略类型声明
- 变量必须进行显示初始化
- 一般默认为val类型变量
字符串
在Scala 中的字符串的类型实际上就是 Java中的 String类,它本身是没有 String 类的。
//字符串连接
print("hello"+word)
//传值字符串
printf("name=%sn", name)
//插值字符串
println(s"name=$name")
//多行字符串
println(
s"""
| Hello
| ${name}
""".stripMargin('|'))
输入与输出
- 从屏幕(控制台)中获取输入
val str:String = scala.io.StdIn.readLine()
- 从文件中获取输入
scala.io.Source.fromFile("input/abc.txt").getLines()
输出:Scala进行文件写操作,用的都是 java中的I/O类
val writer = new PrintWriter(new File("output/aaa.txt"))
writer.write("Hello Scala")
writer.close()
数据类型
Scala是完全面向对象的语言,所以不存在基本数据类型的概念,有的只是任意值对象类型(AnyVal)和任意引用对象类型(AnyRef)
![58671a01f03a428b6907cbc243e143de.png](https://img-blog.csdnimg.cn/img_convert/58671a01f03a428b6907cbc243e143de.png)
类型转换
自动类型转换(隐式转换)
问:Scala中的类型之间没有继承关系怎么可以自动转换?
答:scala中的数值类在编译后对应java中的基本数据类型,所有可以进行自动转换
强制类型转化
var a : Int = 10
Var b : Byte = a.toByte
// 基本上Scala的AnyVal类型之间都提供了相应转换的方法。
字符串类型转化
toString:scala是完全面向对象的语言,所有的类型都提供了toString方法,可以直接转换为字符串
运算符
在Scala中其实是没有运算符的,所有运算符都是方法。
- scala是完全面向对象的语言,所以数字其实也是对象
- 当调用对象的方法时,点.可以省略
- 如果函数参数只有一个,或者没有参数,()可以省略
二、流程控制
分支控制
单分支
if(布尔表达式) {
// 如果布尔表达式为 true 则执行该语句块
}
双分支
if(布尔表达式) {
// 如果布尔表达式为 true 则执行该语句块
} else {
// 如果布尔表达式为 false 则执行该语句块
}
多分支
if(布尔表达式1) {
// 如果布尔表达式1为 true,则执行该语句块
} else if ( 布尔表达式2 ) {
// 如果布尔表达式2为 true,则执行该语句块
}...
} else {
// 上面条件都不满足的场合,则执行该语句块
}
注意:Scala中没有三元运算符,可以用双分支代替
循环控制
for循环
for ( 循环变量 <- 数据集 ) {
循环体
}
//数据集为集合,数组,字符串等类型
循环守卫
for (i <- Range(1,5) if i != 3){
println("i = "+i)
}
// if i != 3 即为循环守卫
循环步长
for (i <- 1 to 5 by 2){
println("i = "+ i)
}
// by 2 即为循环步长
循环嵌套
for (i <- 1 until 5 ; j <- 1 until 5){
println("i = " + i + ", j = " + j )
}
引入变量
for ( i <- Range(1,5); j = i - 1 ) {
println("j = " + j )
}
循环返回值
val result = for ( i <- Range(1,5) ) yield {
i * 2
}
//如果希望for循环表达式的返回值有具体的值,需要使用关键字yield
while循环
while( 循环条件表达式 ) {
循环体
}
and
do {
循环体
} while ( 循环条件表达式 )
循环中断
import scala.util.control.Breaks._
breakable {
for ( i <- 1 to 5 ) {
if ( i == 3 ) {
break
}
println(i)
}
}
//scala中没有break关键字,用函数的方式代替了关键字
三、函数式编程
基础函数编程
基本语法
[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {
函数体
}
private def test( s : String ) : Unit = {
println(s)
}
函数与方法的区别?
在类中声明的函数即为方法,方法可以有重载和重写,而函数没有,但函数可以嵌套的使用而方法不能
函数的至简原则
//函数的基至简原则
def function(name:String):String={
println("基本语法")
return name
}
//(1)return可以省略,Scala会使用函数体的最后一行代码作为返回值
def function1(name:String):String={
println("省略return")
name
}
//(2)如果函数体只有一行代码,可以省略花括号
def function2 (name:String):String= name
//(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
def function3(name:String)=name
//(4)如果有return,则不能省略返回值类型,必须指定
def function4(name:String):String= return name
//(5)如果函数明确声明unit,那么即使函数体中使用return关键字也不起作用
def function5(name:String):Unit=return name
//(6)Scala如果期望是无返回值类型,可以省略等号
def function6(name:String) {println(name+"期望无返回值类型")}
//(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
def function7() {println("无参调用")}
function7
//(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def function8 = println("定义时无()则必省")
function8
//(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
val fun9 = (name:String)=> {println(name+"省略函数名")
}
fun9("小明:")
高级函数编程
函数的调用
//1.函数的调用
def function(name:String):Unit={
println(name+"函数基本调用")
}
function("小明")
//1)函数可以作为值进行传递
//后面加 _ 来调用
val fun11 = function _
fun11("小明")
//指明函数类型来调用
val fun12:String=>Unit=function
fun12("小明")
//2)函数可以作为参数进行传递
def function12(f:(String)=>Unit):String={
f("小明")
"函数参数传递"
}
//如果能够推断出函数是传递而不是调用,则 _ 可以省略
val str = function12(function _)
val str1=function12(function)
println(str)
//3)函数可以作为函数返回值返回
def function13(name1:String):String=>Unit={
println(name1+" 外部函数")
def fun13(name2:String):Unit={
println(name2+"函数作为返回值")
}
//注意要看能否推断出返回值类型,如果返回值类型没有指定,则需用 fun3 _
// fun13 _
fun13
}
function13("小明")("小红")
匿名函数
//2.匿名函数
def function2(a:Int,b:Int,f:(Int)=>Int):Int={
f(a)+f(b)
}
def fun2(x:Int):Int={
x*x
}
println(function2(3, 4, fun2))
//匿名
println(function2(3, 4, (x:Int) => {x*x}))
//(1)参数的类型可以省略,会根据形参进行自动的推导
println(function2(3, 4, (x) => {x*x}))
//(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号。
println(function2(3, 4, x => {x*x}))
//(3)匿名函数如果只有一行,则大括号也可以省略
println(function2(3, 4, x => x*x))
//(4)如果参数只出现一次,则参数省略且后面参数可以用_代替
println(function2(3, 4, _*2))
闭包和函数柯里化
//3.闭包
//如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包
def function3(a:Int)={
def fun3(b:Int)= a+b
fun3 _
}
println(function3(5)(5))
//4.函数柯里化
//把一个参数列表的多个参数,变成多个参数列表。
def function4(a:Int)(b:Int)={
println(a + b)
}
function4(5)(4)
递归
//5.递归
//scala中的递归必须声明函数返回值类型
def function5(x:Int):Int={
if (x<=1) 1
else x * function5(x-1)
}
println(function5(6))
//发散递归容易导致栈溢出,下面是改进
def function51(x:Int,res:Int):Int={
if (x<=1) res
else function51(x-1,x*res)
}
println(function51(6,1))
控制抽象
//6.控制抽象
//1)值调用:把计算后的值传递过去
def foo1(a:Int):Unit={
println(a)
println(a)
}
def function61=()=>{
println("function61....")
20
}
foo1(function61())
//2)名调用:把代码传递过去
def foo2(a: =>Int):Unit={
println(a)
println(a)
}
def function62:()=>Int=()=>{
println("function62----")
40
}
foo2(function62())
惰性函数
//7.惰性函数
//当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。
def function7(a:Int,b:Int)={
println("函数定义")
a+b
}
lazy val res = function7(5,6)
println("执行一些代码")
println("res = "+ res)
四、面向对象编程
基础面向对象编程
包
- Scala中的包和类的物理路径没有关系
- package关键字可以嵌套声明使用
- 子包可以直接访问父包中的内容,而无需import
- Scala中package也可以看作对象,并声明属性和函数
导入
- Scala中使用下划线代替Java中的星号:import java.util._
- Scala中的import语法可以在任意位置使用
- Scala中可以导包,而不是导类:import java.util
- Scala中可以在同一行中导入多个类,简化代码:import java.util.{List, ArrayList}
- Scala中可以屏蔽某个包中的类:import java.sql.{ Date=>_ , Array=> _ , _ }
- Scala中可以给类起别名,简化使用:import java.util.{ArrayList=>AList}
- Scala中可以使用类的绝对路径而不是相对路径:import root.java.util.ArrayList
- 默认情况下,Scala中会导入如下包和对象
import java.lang._
import scala._
import scala.Predef._
类
伴生类和伴生对象?
class : 编译完后只生成一个class文件. xxx.class
object :编译完后生成两个class文件. xxx.class xxx$.class
Scala中没有static语法. 通过object来模仿java的static语法. 并且会有一个单例的对象(xxx$.class)
object修饰类,最终生成了两个字节码文件,我们把object修饰的类称之为伴生类. 把随着伴生类产生的单例对象称之为伴生对象.
后来,我们统一将class修饰的类就称之为伴生类, 把object修饰的类称之为伴生对象。
属性
JavaBean规范: 属性私有,提供公开的get/set方法.
Java中的属性:
private String name ;
public void setName(String name ){this.name = name }
public String getName(){return this.name}
Scala中的属性: 使用默认的修饰符声明了属性, 编译后,属性是通过private修饰的, 并同时提供了该属性的公开的 "get" / "set" 方法.
如果属性声明的时候通过private修饰,编译后,属性也是通过private修饰的, 提供的"get" / "set" 方法也是private修饰的
属性如果通过val声明,必须直接初始化. 编译后,属性通过final修饰.
问题: 按照javaBean规范,属性需要私有化,提供公开的 get / set 方法, Scala怎么办?
很多框架底层会通过反射的方式操作属性的 get / set方法实现对属性值的修改和读取. 如果在Scala中希望生成属性的get/set方法, 可以通过@BeanProperty来标注属性
访问权限
Java 的访问权限:
private : 本类
[default] : 本类 本包
protected : 本类 本包 子类
public : 任意
Scala的访问权限:
private : 本类
private[包] : 本类 包
protected : 本类 子类
[default] : 任意
方法
Java中默认提供的方法: Object类中继承下来的方法
Scala中默认提供的方法: 1.Object类中继承下来的方法 2.PreDef中的方法 println() classOf[] ......
- asInstanceOf[Type] 转换成Type类型 isInstanceOf[Type] 判断是否是Type类型
- apply: apply通常会定义到伴生对象中(object修饰的类中), 用于创建伴生类对象.
构造器
Java的构造方法
class User{
public User(){}
public User(String name){ this.name = name }
}
Scala的构造方法: Scala是完全面向对象的语言. Scala是完全面向函数式编程的语言. 类也是一个 函数. 类名就是函数名, 类体就是函数体. 把这个特殊的函数,就称之为构造函数.
Scala中其实有两种构造函数 主构造函数 : 主要的作用就是完成类体的初始化. 辅助构造函数 : 辅助构造函数就是辅助主构造函数进行类体的初始化. def this(参数列表){} 辅助构造函数必须直接或者间接的调用主构造函数
class User11(addr:String){
val name:String = "zhangsan"
println("constructor user11")
def this(){
this("beijing")
}
def this(name:String ,age:Int){
this("shanghai")
}
}
在Scala中类的主构造函数中,在声明参数的时候,如果使用var 或者val来修饰, 该参数会直接成为类的属性.
class User122( @BeanProperty var name:String ,val age:Int){
def this(username:String){
this(username,40)
}
}
Scala构造函数的定义顺序: 被调用的辅助构造器必须定义当前构造器的前面.
高阶面向对象编程
继承
Scala中的继承也是单继承,且使用extends关键字
封装
1) 将属性进行私有化
2) 提供一个公共的set方法,用于对属性赋值
3) 提供一个公共的get方法,用于获取属性的值
抽象
抽象就是表示 不具体 不完整。 抽象类 抽象方法
- 一个类中如果声明了抽象方法, 那么这个类一定是抽象类
- 一个抽象类中不一定有抽象方法.
- Scala中除了我们熟悉的抽象类 抽象方法外, 还有一个抽象属性.
- 在Scala中,子类继承了抽象类后,抽象类中的抽象方法,在子类中只需要补充完整即可.
- 抽象类中的具体的方法,如果子类要重写,需要通过override修饰符来修饰.
- 一个类中声明了抽象属性,该类必须声明为抽象的.
- 继承了抽象类后,需要将抽象类中的抽象属性补充完整.
- 抽象类中的val声明的具体的属性才能被子类重写.var不可以
- 所谓的抽象属性实际上对应的是Scala为属性默认提供的 "get" / "set" 方法,对抽象属性的重写实际上对属性对应的"get" / "set" 方法的重写.
单例对象
在scala中可以通过object伴生对象来创建单例
class User { // 伴生类
}
object User { // 伴生对象
def apply() = new User() // 构造伴生类对象
}
特质
基础语法
trait 特质名称
class 类名 extends 父类(特质1) with 特质2 with特质3
trait Operator {
}
trait DB{
}
class MySQL extends Operator with DB{
}
Java中的接口: 通过一个特殊的对象,将一些标准或者是规范进行封装. 这个对象称之为接口. 如果一个类需要按照一定的规范完成一些功能,那么该类就需要实现对应的接口
Scala中的特质: 通过一个特殊的对象, 将一些类共通的特征抽取出来进行封装,这个对象称之为特质. 如果一个类符合某个特质,那么就可以将对应的特质 "混入"到该类中.
可以将Scala中的特质理解为Java中的接口. 又可以理解是Java中的抽象类.
如果将Scala中的特质理解为接口:
- 接口可以继承接口. 特质可以继承特质
- 接口可以多实现. 特质可以多混入
如果将Scala中的特质理解为抽象类:
- 抽象类中可以有抽象方法,抽象属性 , 特质也可以声明抽象方法 抽象属性
- 类是单继承. "特质也是单继承"
动态混入
val mysql = new MySQL with Operator
//在创建对象的时候混入特质
初始化叠加
初始化顺序: 按照特质混入的顺序从左到右进行初始化
功能化叠加
功能执行顺序: 按照混入特质的顺序从右往左执行.
五、集合
Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质。对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本。
不可变集合包:scala.collection.immutable
可变集合包:scala.collection.mutable
数组
不可变数组
//创建数组
val arr01 = new Array[Int](4)
val arr1 = Array(1,2,3,4)
val arr2 = Array(5,6,7,8)
// 添加数组元素,创建新数组
val arr3: Array[Int] = arr1 :+ 5
val arr4: Array[Int] = arr1 ++ arr2
// 多维数组
var myMatrix = Array.ofDim[Int](3,3)
// 合并数组
val arr6: Array[Int] = Array.concat(arr1, arr2)
// 创建指定范围的数组
val arr7: Array[Int] = Array.range(0,2)
// 创建并填充指定数量的数组
val arr8:Array[Int] = Array.fill[Int](5)(-1)
可变数组
//创建数组
val buffer = new ArrayBuffer[Int]
val buffer1 = ArrayBuffer(1,2,3,4)
val buffer2 = ArrayBuffer(5,6,7,8)
//增加数据
buffer.append(1,2)
//修改数据
buffer.update(0,5)
buffer(1)=6
//删除数据
val i:Int = buffer.remove(2)
buffer.remove(2,2)
// 使用 ++ 运算符会产生新的集合数组
val buffer4: ArrayBuffer[Int] = buffer1 ++ buffer2
// 使用 ++= 运算符会更新之前的集合,不会产生新的数组
val buffer5: ArrayBuffer[Int] = buffer1 ++= buffer
// 将不可变数组转换为可变数组
val buffer1: mutable.Buffer[Int] = array.toBuffer
// 将可变数组转换为不可变数组
val array1: Array[Int] = buffer.toArray
Seq集合
不可变List
//创建集合
val list = List(1,2,3,4)
val list3: List[Int] = 1::2::3::Nil
// 增加数据
val list1: List[Int] = list :+ 1
val list2: List[Int] = 1 +: list
//修改数据
val list3: List[Int] = list.updated(1,5)
//空集合
List()=nil
// 合并集合
val list5: List[Int] = List.concat(list3, list4)
// 创建一个指定重复数量的元素列表
val list6: List[String] = List.fill[String](3)("a")
可变List
// 可变集合
val buffer = new ListBuffer[Int]()
val buffer1 = ListBuffer(1,2,3,4)
val buffer2 = ListBuffer(5,6,7,8)
// 增加数据
buffer.append(1,2,3,4)
val buffer3: ListBuffer[Int] = buffer1 :+ 5
val buffer4: ListBuffer[Int] = buffer1 += 5
val buffer5: ListBuffer[Int] = buffer1 ++ buffer2
val buffer6: ListBuffer[Int] = buffer1 ++= buffer2
// 修改数据
buffer.update(1,3)
// 删除数据
buffer.remove(2)
buffer.remove(2,2)
// 获取数据
println(buffer(1))
// 遍历集合
buffer.foreach(println)
// 可变集合转变为不可变集合
val list1: List[Int] = buffer.toList
// 不可变集合转变为可变集合
val buffer1: mutable.Buffer[Int] = list.toBuffer
Set集合
不可变Set
//创建集合
val set1 = Set(1,2,3,4)
val set2 = Set(5,6,7,8)
// 增加数据
val set3: Set[Int] = set1 + 5 + 6
val set4: Set[Int] = set1.+(6,7,8)
// 删除数据
val set5: Set[Int] = set1 - 2 - 3
val set6: Set[Int] = set1 ++ set2
val set7: Set[Int] = set2 ++: set1
可变集合Set
import scala.collection.mutable
//创建集合
val set1 = mutable.Set(1,2,3,4)
val set2 = mutable.Set(5,6,7,8)
// 增加数据
set1.add(5)
// 添加数据
set1.update(6,true)
println(set1.mkString(","))
// 删除数据
set1.update(3,false)
println(set1.mkString(","))
// 删除数据
set1.remove(2)
println(set1.mkString(","))
// 遍历数据
set1.foreach(println)
// 交集
val set3: mutable.Set[Int] = set1 & set2
// 差集
val set4: mutable.Set[Int] = set1 &~ set2
Map集合
不可变Map
//创建map
val map1 = Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = Map( "d" -> 4, "e" -> 5, "f" -> 6 )
// 添加数据
val map3 = map1 + ("d" -> 4)
println(map1 eq map3) // false
// 删除数据
val map4 = map3 - "d"
println(map4.mkString(","))
val map5: Map[String, Int] = map1 ++ map2
println(map5 eq map1)
println(map5.mkString(","))
val map6: Map[String, Int] = map1 ++: map2
println(map6 eq map1)
println(map6.mkString(","))
// 修改数据
val map7: Map[String, Int] = map1.updated("b", 5)
println(map7.mkString(","))
// 遍历数据
map1.foreach(println)
// 创建空集合
val empty: Map[String, Int] = Map.empty
println(empty)
// 获取指定key的值
val i: Int = map1.apply("c")
println(i)
可变Map
import scala.collection.mutable
//创建map
val map1 = mutable.Map( "a" -> 1, "b" -> 2, "c" -> 3 )
val map2 = mutable.Map( "d" -> 4, "e" -> 5, "f" -> 6 )
// 添加数据
map1.put("d", 4)
val map3: mutable.Map[String, Int] = map1 + ("e" -> 4)
println(map1 eq map3)
val map4: mutable.Map[String, Int] = map1 += ("e" -> 5)
println(map1 eq map4)
// 修改数据
map1.update("e",8)
map1("e") = 8
// 删除数据
map1.remove("e")
val map5: mutable.Map[String, Int] = map1 - "e"
println(map1 eq map5)
val map6: mutable.Map[String, Int] = map1 -= "e"
println(map1 eq map6)
// 清除集合
map1.clear()
//基本操作
val set: Set[(String, Int)] = map1.toSet
val list: List[(String, Int)] = map1.toList
val seq: Seq[(String, Int)] = map1.toSeq
val array: Array[(String, Int)] = map1.toArray
println(map1.get("a"))
println(map1.getOrElse("a", 0))
println(map1.keys)
println(map1.keySet)
println(map1.keysIterator)
println(map1.values)
println(map1.valuesIterator)
元组
// 创建元组,使用小括号
val tuple = (1, "zhangsan", 30)
// 根据顺序号访问元组的数据
println(tuple._1)
println(tuple._2)
println(tuple._3)
// 迭代器
val iterator: Iterator[Any] = tuple.productIterator
// 根据索引访问元素
tuple.productElement(0)
// 获取整体
println(tuple)
// 如果元组的元素只有两个,那么我们称之为对偶元组,也称之为键值对
val kv: (String, Int) = ("a", 1)
val kv1: (String, Int) = "a" -> 1
队列
val que = new mutable.Queue[String]()
// 添加元素
que.enqueue("a", "b", "c")
val que1: mutable.Queue[String] = que += "d"
println(que eq que1)
// 获取元素
println(que.dequeue())
println(que.dequeue())
println(que.dequeue())
并行
val result1 = (0 to 100).map{x => Thread.currentThread.getName}
//并行多线程启动
val result2 = (0 to 100).par.map{x => Thread.currentThread.getName}
常用方法
1) 常用方法
object ScalaCollection{
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
// 集合长度
println("size =>" + list.size)
println("length =>" + list.length)
// 判断集合是否为空
println("isEmpty =>" + list.isEmpty)
// 集合迭代器
println("iterator =>" + list.iterator)
// 循环遍历集合
list.foreach(println)
// 将集合转换为字符串
println("mkString =>" + list.mkString(","))
// 判断集合中是否包含某个元素
println("contains =>" + list.contains(2))
// 取集合的前几个元素
println("take =>" + list.take(2))
// 取集合的后几个元素
println("takeRight =>" + list.takeRight(2))
// 查找元素
println("find =>" + list.find(x => x % 2== 0))
// 丢弃前几个元素
println("drop =>" + list.drop(2))
// 丢弃后几个元素
println("dropRight =>" + list.dropRight(2))
// 反转集合
println("reverse =>" + list.reverse)
// 去重
println("distinct =>" + list.distinct)
}
}
2) 衍生集合
object ScalaCollection{
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
val list1 = List(3,4,5,6)
// 集合头
println("head => " + list.head)
// 集合尾
println("tail => " + list.tail)
// 集合尾迭代
println("tails => " + list.tails)
// 集合初始化
println("init => " + list.init)
// 集合初始化迭代
println("inits => " + list.inits)
// 集合最后元素
println("last => " + list.last)
// 集合并集
println("union => " + list.union(list1))
// 集合交集
println("intersect => " + list.intersect(list1))
// 集合差集
println("diff => " + list.diff(list1))
// 切分集合
println("splitAt => " + list.splitAt(2))
// 滑动
println("sliding => " + list.sliding(2))
// 滚动
println("sliding => " + list.sliding(2,2))
// 拉链
println("zip => " + list.zip(list1))
// 数据索引拉链
println("zipWithIndex => " + list.zipWithIndex)
}
}
3) 计算函数
object ScalaCollection{
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
val list1 = List(3,4,5,6)
// 集合最小值
println("min => " + list.min)
// 集合最大值
println("max => " + list.max)
// 集合求和
println("sum => " + list.sum)
// 集合乘积
println("product => " + list.product)
// 集合简化规约
println("reduce => " + list.reduce((x:Int,y:Int)=>{x+y}))
println("reduce => " + list.reduce((x,y)=>{x+y}))
println("reduce => " + list.reduce((x,y)=>x+y))
println("reduce => " + list.reduce(_+_))
// 集合简化规约(左)
println("reduceLeft => " + list.reduceLeft(_+_))
// 集合简化规约(右)
println("reduceRight => " + list.reduceRight(_+_))
// 集合折叠
println("fold => " + list.fold(0)(_+_))
// 集合折叠(左)
println("foldLeft => " + list.foldLeft(0)(_+_))
// 集合折叠(右)
println("foldRight => " + list.foldRight(0)(_+_))
// 集合扫描
println("scan => " + list.scan(0)(_+_))
// 集合扫描(左)
println("scanLeft => " + list.scanLeft(0)(_+_))
// 集合扫描(右)
println("scanRight => " + list.scanRight(0)(_+_))
}
}
4) 功能函数
object ScalaCollection{
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
//map: 集合映射,将集合通过指定的转换规则转换成新的集合
def transform(i:Int):Int ={
i * 2
}
println("map => " + list.map(transform)) // 使用自己定义函数
println("map => " + list.map(x=>{x*2})) // 匿名函函数
println("map => " + list.map(x=>x*2))
println("map => " + list.map(_*2))
//flatten: 集合扁平化,所谓的扁平化就是将整体拆分成一个一个的个体
// 将如下集合处理成 List(1,2,3,4)
val list1 = List(
List(1,2),
List(3,4)
)
println("flatten =>" + list1.flatten)
// 将如下集合处理成List(1,2,3,4)
val list2 = List(List(List(1,2)),List(List(3,4)))
println("flatten =>" + list2.flatten.flatten) // 递归
// flatMap: 集合扁平映射
// 将如下集合处理成 List(2,4,6,8)
val list3 = List( List(1,2),List(3,4))
// 方法一
println("flatMap =>" + list3.flatten.map(_ * 2)) // 先flatten再map
def transform1(list:List[Int]):List[Int] = {
list.map( _ * 2)
}
// 方法二
println("flatMap =>" +list3.flatMap(transform1)) //使用自己定义函数
// 方法三
println("flatMap =>" +list3.flatMap(list=>list.map(_*2))) // 匿名函数
println("flatMap =>" +list3.flatMap(_.map(_ * 2)))
// 将如下集合处理成List("hello", "scala","hello","spark")
val list4 = List("hello scala","hello spark")
println("flatMap =>" +list4.flatten) //默认拆分成一个一个的字符
println("flatMap =>" +list4.flatMap(_.split(" "))) //自己定义扁平规则
//filter: 集合过滤数据,按照指定的规则对集合中的每条数据进行筛选过滤,满足条件的保留
//,不满足条件的丢弃
val list5 = List(1,2,3,4)
println("filter =>" +list5.filter(_ % 2 == 0)) //过滤偶数
val list6 = List("hello","spark","scala","hadoop")
println("filter =>" +list6.filter(_.startsWith("s"))) //过滤”s”开头的单词
// groupBy: 集合分组数据,按照指定的规则对集合中的每个数据进行分组,指定的规则其实就
// 是一个函数,这个函数返回的结果就是分组的 key.
val list7 = List(1,2,3,4)
println("groupBy =>" +list7.groupBy(_ % 2))
val list8 = List("hello","hello","scala","haha")
println(list8.groupBy(word=>word)) // 单词分组
println("groupBy =>" +list8.groupBy(_.charAt(0))) // 单词首字母分组
//sortBy: 集合排序,将集合中每个数据按照指定的规则进行排序
val list9 = List(3,1,4,2)
println(list9.sortBy(num => num))
println(list9.sortBy(num => -num)) //降序排序
println("sortBy =>" + list.sortBy(num=>num)(Ordering.Int.reverse))//降序排序
val list10 = List((30,"zhangsan"),(20,"wangwu"),(20,"lisi"))
println(list10.sortBy(t => t)(Ordering.Tuple2(Ordering.Int.reverse, Ordering.String)))
//sortWith: 自定义排序
// 大 > 小 降序
// 小 < 大 升序
println(ints2.sortWith((left, right) => {
//left._1 > right._1 // 降序
// left._1 < right._1 // 升序
if(left._1 == right._1){ //
left._2 > right._2
}else{
left._1 > right._1
}
}))
}
}
六、模式匹配
基本语法
var operator: Char = '+'
var result = operator match {
case '+' => a + b
case '-' => a - b
case '*' => a * b
case '/' => a / b
case _ => "illegal"
}
匹配规则
匹配常量
def describe(x:Any)=x match{
case 5 => "Int five"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
}
匹配类型
def describe(x: Any) = x match {
case i: Int => "Int"
case s: String => "String hello"
case m: List[_] => "List"
case c: Array[Int] => "Array[Int]"
case someThing => "something else " + someThing
}
匹配数组
for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1), Array("hello", 90))) { // 对一个数组集合进行遍历
val result = arr match {
case Array(0) => "0" //匹配Array(0) 这个数组
case Array(x, y) => x + "," + y //匹配有两个元素的数组,然后将将元素值赋给对应的x,y
case Array(0, _*) => "以0开头的数组" //匹配以0开头的数组
case _ => "something else"
}
println("result = " + result)
}
匹配列表
for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0), List(88))) {
val result = list match {
case List(0) => "0" //匹配List(0)
case List(x, y) => x + "," + y //匹配有两个元素的List
case List(0, _*) => "0 ..."
case _ => "something else"
}
println(result)
}
val list: List[Int] = List(1, 2, 5, 6, 7)
list match {
case first :: second :: rest => println(first + "-" + second + "-" + rest)
case _ => println("something else")
}
匹配元组
for (tuple <- Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {
val result = tuple match {
case (0, _) => "0 ..." // 第一个元素是0的元组
case (y, 0) => "" + y + "0" // 匹配后一个元素是0的对偶元组
case (a, b) => "" + a + " " + b
case _ => "something else" //默认
}
println(result)
}
匹配对象
val user: User = User("zhangsan", 11)
val result = user match {
case User("zhangsan", 11) => "yes"
case _ => "no"
}
//样例类
case class User(name: String,age: Int)
样例类
- 样例类就是使用case关键字声明的类
- 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如apply、unapply、toString、equals、hashCode和copy。
- 样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法。
- 构造器中的每一个参数都成为val,除非它被显式地声明为var(不建议这样做)
应用场景
//变量声明
val (x, y) = (1, 2)
val Array(first, second, _*) = Array(1, 7, 2, 9)
val Person(name, age) = Person("zhangsan", 16)
case class Person(name: String, age: Int)
//循环匹配
val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
for ((k, v) <- map if v >= 1) { //直接将map中的k-v遍历出来
println(k + " -> " + v) //3个
}
//函数参数
val list = List(("a",1),("b",2),("c",3))
val newList1: List[(String, Int)] = list.map {
case (word, count) => {
(word, count * 2)
}
}
偏函数
基本语法
// 声明偏函数
val pf: PartialFunction[Int, String] = { case 1 => "one" }
// 应用偏函数
println(List(1, 2, 3, 4).collect(pf))
七、异常处理
Scala中的异常不区分所谓的编译时异常和运行时异常,也无需显示抛出方法异常,所以Scala中没有throws关键字。
object ScalaException {
def main(args: Array[String]): Unit = {
try {
var n= 10 / 0
}catch {
case ex: ArithmeticException=>{
// 发生算术异常
println("发生算术异常")
}
case ex: Exception=>{
// 对异常处理
println("发生了异常1")
}
}finally {
println("finally")
}
}
}
八、隐式转换
Scala在程序编译错误时,可以通过隐式转换中类型转换机制尝试进行二次编译,将本身错误无法编译通过的代码通过类型转换后编译通过。
隐式函数
implicit def transform( d : Double ): Int = {
d.toInt
}
var d : Double = 2.0
val i : Int = d
println(i)
}
隐式参数与隐式变量
object ScalaImplicit {
// 隐式参数
def regUser(name:String)(implicit password:String="666"):Unit = {
println(s"注册用户: $name ,默认密码: $password ")
}
//TODO 隐式变量
implicit val newPassword:String = "888"
//如果想要使用隐式参数进行处理, 那么调用函数时, 不需要使用小括号调用
regUser("zhangsan")
//如果想要使用参数的默认值或者自己传入值,就加上小括号
regUser("zhangsan")()
regUser("zhangsan")("999")
//TODO 隐式参数和隐式变量举例
//集合的sortBy方法
}
隐式类
- 其所带的构造参数有且只能有一个
- 隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。
implicit class User( emp : Emp) {
def insertUser(): Unit = {
println("insert user...")
}
}
隐式机制
所谓的隐式机制,就是一旦出现编译错误时,编译器会从哪些地方查找对应的隐式转换规则
- 当前代码作用域
- 当前代码上级作用域
- 当前类所在的包对象
- 当前类(对象)的父类(父类)或特质(父特质)
九、泛型
泛型不可变
class Test[T] { }
val test1 : Test[User] = new Test[User] // OK
val test2 : Test[User] = new Test[Parent] // Error
val test3 : Test[User] = new Test[SubUser] // Error
泛型协变
// 泛型协变[+T]:就是将子类型当成父类型来使用
class Test[+T] { }
val test1 : Test[User] = new Test[User] // OK
val test2 : Test[User] = new Test[Parent] // Error
val test3 : Test[User] = new Test[SubUser] // OK
泛型逆变
//泛型逆变[-T]: 将父类型当成子类型来使用
class Test[-T] { }
val test1 : Test[User] = new Test[User] // OK
val test2 : Test[User] = new Test[Parent] // OK
val test3 : Test[User] = new Test[SubUser] // Error
泛型边界
def test[A]( a : A ): Unit = {
println(a)
}
test[User](parent) // Error
test[User](user) // OK
test[User](subuser) // OK
泛型上限
//对比java ? extends User
def test[A<:User]( a : A ): Unit = {
println(a)
}
泛型下限
//对比java ? super User
def test[A>:User]( a : A ): Unit = {
println(a)
}
上下文限定
//函数f的泛型为[A:Test],也就是说后面需要一个隐式转换的Test[A]的参数A
def f[A : Test](a: A) = println(a)
//此隐式转换符合要求
implicit val test : Test[User] = new Test[User]
//f的参数类型为User
f( new User() )