Scala学习笔记
第一个scala程序
**
* object: 关键字,声明一个单例对象(伴生对象)
*/
object HelloWorld {
/**
* main: 方法,从外部可以直接调用执行的方法
* def 方法名称(参数名称: 参数类型): 返回值类型 = {方法体}
* []: 泛型
* @param args
*/
def main(args: Array[String]): Unit = {
println("hello world")
System.out.println("hello scala from java")
}
}
Scala和Java的区别
/**
* java实现
*/
public class Student {
private String name;
private int age;
private static String school = "学校";
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void printInfo(){
System.out.println(this.name + " " + this.age + " " + Student.school);
}
public static void main(String[] args) {
Student student1 = new Student("张三", 23);
Student student2 = new Student("李四", 24);
student1.printInfo();
student2.printInfo();
}
}
/**
* Scala实现
* student(入口类),伴生类;student$(伴生类),伴生对象所属类
* 伴生类,伴生对象,同时实现,必须名称一样,在同一个文件内
* @param name
* @param age
*/
class Student(name: String, age: Int) {
def printInfo(): Unit = {
println(name + " " + age + " " + Student.school)
}
}
//引入伴生对象
object Student{
val school: String = "学校"
def main(args: Array[String]): Unit = {
val student1 = new Student("张三", 23)
val student2 = new Student("李四", 23)
student1.printInfo()
student2.printInfo()
}
}
变量和常量(能用常量的地方不用变量)
- 变量基本语法: var 变量名 [: 变量类型] = 初始值, var i: Int = 10
- 常量基本语法: val 常量名 [: 常量类型] = 初始值, val j: Int = 20
- 声明变量时,类型可以省略,编译器自动推导,即类型推导
- 类型确定后,就不能修改,说明scala是强数据类型语言
- 变量声明时,必须要有初始值
- 在声明|定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改
- “*” :用于将一个字符串复制多次拼接"a" * 3 输出 “aaa”
- printf:格式化输出
- s" " : 模板字符串
- f" ":格式化模板字符串
- raw" ": 按原始字符串输出
- 三引号表示字符串,保持多行字符串的原格式输出
val name: String = "张三"
val age: Int = 25
println(s"我叫${name}今年${age}岁")
val num: Double = 2.1231
println(f"The num is ${num}%2.2f")
println(raw"The num is ${num}%2.2f")
val sql =
s"""
|select *
|from test
|where name = ${name}
|and age > ${age}
|""".stripMargin //stripMargin:忽略编辑
println(sql)
————————————————————————————————————输出
我叫张三今年25岁
The num is 2.12
The num is 2.1231%2.2f
select *
from test
where name = 张三
and age > 25
键盘输入
import scala.io.StdIn
object Test02 {
def main(args: Array[String]): Unit = {
println("请输入名字:")
val name: String = StdIn.readLine()
println("请输入年龄")
val age = StdIn.readInt()
println(s"欢迎${age}岁的${name}")
}
}
文件读写
import java.io.{File, PrintWriter}
import scala.io.Source
object Test03_FileIo {
def main(args: Array[String]): Unit = {
//从文件中读取数据
Source.fromFile("src/main/resources/test.txt").foreach(print)
//将数据写入文件
val writer = new PrintWriter(new File("src/main/resources/output.txt"))
writer.write("hello Scala from java writer")
writer.close()
}
}
数据类型
整数类型
- Byte::1字节
- Short::2字节
- Int:4字节
- Long:8字节
- Boolean:1个字节
- 整数默认类型:Int
- 浮点类型默认:Double
- Nothing:Nothing类型在scala的类层级最低端,它是任何其他类型的子类型,当一个函数,我们确定没有正常的返回值,我们就可以用nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其他的函数或者变量(兼容性)
流程控制
import scala.util.control.Breaks
import scala.util.control.Breaks._
object Test04 {
def main(args: Array[String]): Unit = {
val i: Int = 100
val y: Int = if (i < 12){
println(i)
1
} else{
println(i)
2
}
println(y)
//循环遍历
for (i <- 1 to 10){
println(i + "hello world")
}
for (i <- Range(0, 10)){
println(i + "hello world")
}
for (i <- 0 until 10){
println(i + "hello world")
}
println("----------------------")
for (i <- Array(1,2,30,4)){
println(i)
}
for (i <- List(1,2,30,4)){
println(i)
}
for (i <- Set(1,2,30,4)){
println(i)
}
//循环守卫,相当于java continue 功能
for (i <- 1 to 10 if i != 3){
println(i)
}
println("--------------------")
//循环步长
for (i <- 1 to 10 by 2){
println(i)
}
println("-------------------------")
for (i <- 10 to 1 by -1){
println(i)
}
for (i <- 1 to 10 reverse){
println(i)
}
//by 0.5 循环步长
for ( i <- 1.0 to 10.0 by 0.5){
println(i)
}
//嵌套循环
for (i <- 1 to 3){
for (j <- 1 to 3){
println("i=" + i + ", j=" + j)
}
}
println("--------------------------")
for (i <- 1 to 5; j <- 1 to 4){
println("i=" + i + ", j=" + j)
}
println("--------------------------")
for (i <- 1 to 9){
for (j <- 1 to i){
print(s"$j + $i = ${i * j} \t")
}
println()
}
for (i <- 1 to 9; j <- 1 to i){
print(s"$j + $i = ${i * j} \t")
if (j == i) println()
}
//引入变量
for (i <- 1 to 9; j = 9 -i){
println(i + "---" + j)
}
for {
i <- 1 to 5
j = 5 - i
}{
println(i + "---" + j)
}
for (i <- 1 to 9; j = 9 - i){
println(" " * j + "*" * (2 * i -1) )
}
for (i <- 1 to 9; stars = 2 * i -1; spaces = 9 -i){
println(" " * spaces + "*" * stars)
}
for (stars <- 1 to 17 by 2; spaces = (17 - stars) / 2){
println(" " * spaces + "*" * stars)
}
val b = for (i <- 1 to 10) yield i
println(b)
//跳出循环
Breaks.breakable(
for (i <- 1 until 5){
if (i == 3){
Breaks.break()
}
println(i)
}
)
breakable(
for (i <- 1 until 5){
if (i == 3){
break()
}
println(i)
}
)
}
}
函数和方法的区别
- 为完成某一功能的程序语句的集合,称为函数
- 类中的函数称之方法
object Test05 {
def main(args: Array[String]): Unit = {
//可变参数
def f1(str: String*): Unit = {
println(str)
}
f1("a","b","c")
}
//多个参数,可变参数一般放置在最后
def f2(str1: String, str2: String*): Unit = {
println(s"str1=${str1}, str2=${str2}")
}
f2("a","b","c","d")
//默认参数,一般放置在参数列表最后
def f3(name: String = "李四"): Unit = {
println(name)
}
f3()
f3("王五")
//带名参数
def f4(name: String, age: Int): Unit = {
println(s"名字是${name}今年${age}岁")
}
f4(age = 18, name = "张三")
}
函数至简原则
//匿名函数简化
f((name) => {println(name)})
f(name => {println(name)})
f(name => println(name))
f(println(_))
//如果可以推断出,当前传入的println是一个函数体,而不是调用语句,可以直接省略下划线
f(println)
object Test07 {
def main(args: Array[String]): Unit = {
val arr: Array[Int] = Array(12, 45, 75, 98)
//对数组进行处理,将操作抽象出来,处理完毕之后的结果返回一个新的数组
def arrayOperation(array: Array[Int], op: Int => Int): Array[Int] = {
for (elem <- array) yield op(elem)
}
//定义一个加1操作
def addOne(elem: Int): Int = {
elem + 1
}
println(arrayOperation(arr, addOne).mkString(","))
println(arrayOperation(arr, _ * 2).mkString(","))
val fun = (i: Int, s: String, c: Char) => {
if (i == 0 && s == "" && c == '0') false else true
}
println(fun(0, "", '0'))
println(fun(1, "", '0'))
println(fun(0, "", '1'))
def f1(char: Char): Boolean={true}
def f2(string: String): Char=>Boolean = {
f1 _
}
def f3(i: Int): String=>(Char=>Boolean) = {
def f2(s: String): Char=>Boolean = {
def f1(c: Char): Boolean={
if (i == 0 && s == "" && c == '0') false else true
}
f1
}
f2
}
println("------------------------------")
println(f3(1)("")('0'))
//简写
def f4(i: Int): String=>(Char=>Boolean) = {
s => c => if (i == 0 && s == "" && c == '0') false else true
}
//柯里化
def f5(i: Int)(s: String)(c: Char): Boolean = {
if (i == 0 && s == "" && c == '0') false else true
}
}
}
函数柯里化&闭包
- 闭包:函数式编程的标配
- 闭包:如果一个函数,访问到了它外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包
- 函数柯里化:把一个参数列表的多个参数,变成多个参数列表
- 递归:一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用
object Test09 {
def main(args: Array[String]): Unit = {
println(fact(5))
println(tailFact(5))
}
def fact(n: Int):Int = {
if (n == 0) return 1;
fact(n - 1) * n;
}
//尾递归
def tailFact(n: Int): Int = {
@tailrec
def looop(n: Int, currRes: Int): Int = {
if (n == 0) return currRes
looop(n - 1, currRes * n)
}
looop(n, 1)
}
}
控制抽象
- 值调用:把计算后的值传递过去
- 名调用:把代码传递过去
//1.传值调用
def f0(a: Int): Unit = {
println("a: " + a)
}
f0(1)
//2.传名调用(传递代码块)
def f1(a: =>Int): Unit = { // =>Int 表示代码块类型(一段代码块),返回值是Int
println("a: " + a)
println("a: " + a)
}
def f2(): Int = {
println("f2调用")
12
}
f1(f2())
实现while循环
object MyWhile {
def main(args: Array[String]): Unit = {
var n = 10
while (n >= 1){
println(n)
n -= 1
}
//用闭包实现一个函数,将代码块作为参数传入,递归调用
def myWhile(condition: =>Boolean): (=>Unit) =>Unit = {
//内层函数需要递归调用
def doLoop(op: => Unit): Unit = {
if (condition){
op
myWhile(condition)(op)
}
}
doLoop _
}
println("*********************")
n = 10
myWhile(n >= 1)({
println(n)
n -= 1
})
//用匿名函数实现
def myWhile2(condition: =>Boolean): (=>Unit) =>Unit = {
//内层函数需要递归调用
op => {
if (condition){
op
myWhile2(condition)(op)
}
}
}
println("*********************")
n = 10
myWhile2(n >= 1){
println(n)
n -= 1
}
//柯里化实现
def myWhile3(condition: => Boolean)(op: => Unit): Unit = {
if (condition){
op
myWhile3(condition)(op)
}
}
}
}
惰性加载
- 当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行,这种函数我们称之为惰性函数。
def main(args: Array[String]): Unit = {
lazy val result:Int = sum(1, 2)
println("1. 函数调用")
println("2. result = " + result)
println("4. result = " + result)
}
def sum(a: Int, b: Int): Int = {
println("3. sum调用")
a + b
}
输出结果:
1. 函数调用
3. sum调用
2. result = 3
4. result = 3
面向对象
Scala的面向对象思想和Java的面向对象思想和概念是一致的。
Scala中语法和Java不同,补充了更多的功能。
- 包定义
//用嵌套风格定义包
package com{
import com.pan.scala.Inner
//在外层包中定义单例对象
object Outer{
var out: String = "out"
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
package pan{
package scala{
//在内层包中定义单例对象
object Inner{
val in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out)
Outer.out = "outer"
println(Outer.out)
}
}
}
}
}
//在同一文件中定义多个包
package a{
package b{
import com.pan.scala.Inner
object Test{
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
}
}
- 包对象
- 在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问。
- 导包说明
- 通配符导入: import java.util._
- 给类起别名:import java.util.{ArrayList =>AL}
- 屏蔽类:import java.util.{ArrayList=> _ , _}
- 构造器
- Scala类的构造器包括:主构造器和辅助构造器
- 辅助构造方法不能直接构建对象,必须直接或间接调用主构造方法
//基本语法
class 类名(形参列表){ //主构造器
//类体
def this(形参列表){ //辅助构造器,可以有多个
}
def this(形参列表){
}
}
- 构造器参数
- Scala类的主构造器函数的形参包括三种类型:未用任何修饰符,var修饰,val修饰
- 未用任何修饰符修饰:这个参数就是局部变量
- var修饰参数:作为类的成员属性使用,可以修改
- val修饰参数:作为类的只读属性使用,不能修改
object Test14 {
def main(args: Array[String]): Unit = {
val student2 = new Student2
student2.name = "张三"
student2.age = 15
println(s"Student2: name = ${student2.name}, age = ${student2.age}")
val student3 = new Student3("李四", 16)
println(s"student3: name = ${student3.name}, age = ${student3.age}")
val student4 = new Student4("李四1", 16)
//println(s"student4: name = ${student4.name}, age = ${student4.age}")
student4.printInfo()
val student5 = new Student5("李四", 16)
println(s"student5: name = ${student5.name}, age = ${student5.age}")
val student6 = new Student6("李四", 16)
println(s"student6: name = ${student6.name}, age = ${student6.age}")
student6.printInfo()
}
}
class Student2{
var name: String = _
var age: Int = _
}
class Student3(var name: String, var age: Int)
//主构造器参数无修饰
class Student4(name: String, age: Int){
def printInfo(): Unit ={
println(s"studnet4: name = ${name}, age = ${age}")
}
}
class Student5(val name: String, val age: Int) //常量
class Student6(var name: String, var age: Int){
var school: String = _
def this(name: String, age: Int, school: String){
this(name, age)
this.school = school
}
def printInfo(): Unit ={
println(s"studnet6: name = ${name}, age = ${age}, school = ${school}")
}
}
- 单例对象
- 单例对象采用object关键字声明
- 单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致
- 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问
object Test18 {
def main(args: Array[String]): Unit = {
/*val student = new Student18("张三", 19)
student.printInfo()*/
val student = Student18.newStudent("张三", 20)
student.printInfo()
val student1 = Student18.apply("张三", 20)
student1.printInfo()
val student2 = Student18("张三", 21) //调用伴生对象的 apply(底层优化) 方法(简写)
student2.printInfo()
}
}
class Student18 private (val name: String, val age: Int){ //private 主构造器私有化
def printInfo(): Unit ={
println(s"studnet6: name = ${name}, age = ${age}, school = ${Student18.school}")
}
}
object Student18{
val school: String = "FDB"
//定义一个类的对象实例的创建方法
def newStudent(name: String, age: Int): Student18 = new Student18(name, age)
def apply(name: String, age: Int): Student18 = new Student18(name, age)
}
特质(Trait)
- Scala语言中,采用特质(trait)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。
- Scala中的trait中即可以有抽象属性和方法,也可以有具体属性和方法,,一个类可以混入多个特质,,类似于java中的抽象类。
- Scala引入trait特征,第一个可以代替java的接口,第二个也是对单继承机制的一种补充。
- 基本语法:
- 没有父类:class 类名 extends 特质1 with 特质2
- 有父类:class 类名 extends 父类 with 特质1 with 特质2
//动态混入(特质)
val studentWithTalent = new Student21 with Talent {
override def singing(): Unit = println("student is good at singing")
override def dancing(): Unit = println("student is good at dancing")
}
- 特质和抽象类的区别
- 优先使用特质,一个类扩展多个特质是很方便的,但却只能扩展一个抽象类
- 如果你需要构造函数参数,使用抽象类,因为抽象类可以定义带参数的构造函数,而特质不行(有无参构造)
- 类型检查和转换
- obj.isInstanceOf[T] :判断obj是不是T类型
- obj.asInstanceOf[T] :将obj强转成T类型
- classOf :获取对象的类名
- 自身类型
/**
* 自身类型
*/
object Test_TraitSelfType {
def main(args: Array[String]): Unit = {
val user = new RegisterUser("张三", "122131")
user.insert()
}
}
class User(val name: String, val password: String)
trait UserDao {
//类似于依赖注入
_: User =>
def insert(): Unit = {
println(s"insert into db: ${this.name} ")
}
}
class RegisterUser(name: String, password: String) extends User(name, password) with UserDao
- 枚举类和应用类
- 枚举类:继承Enumeration
- 应用类:继承App
集合
- Scala的集合有三大类,所有集合都扩展自Iterable特质
- 序列Seq
- 集Set
- 映射Map
- Scala都同时提供了可变和不可变版本
-
不可变集合:scala.collection.immutable,类似java中的String对象
-
可变集合:scala.collection.mutable,类似StringBuilder
-
建议:在操作集合的时候,不可变用符号,可变用方法
-
数组
- 不可变数组
- 定义:val arr1 = new Arry[Int] (10);val arr2 = Array(1,2,3,4)(调用伴生对象的apply方法)
- new 是关键字
- [Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any
- (10),表示数组的大小,确定后就不可以变化
object Test01_ImmutableArray {
def main(args: Array[String]): Unit = {
val arr: Array[Int] = new Array[Int](5)
arr(0) = 112
arr(3) = 142
for (i <- arr){
println(i)
}
val arr2 = Array(1,2,3,4)
arr2(1) = 10
println("*********************")
arr2.foreach(println)
println("-----------------------")
for(i <- 0 until arr2.length){
println(arr2(i))
}
println("-----------------------")
for (i <- arr2.indices){
println(arr2(i))
}
println("-----------------------")
for (i <- arr2){
println(i)
}
val iterator = arr2.iterator
while (iterator.hasNext){
println(iterator.next())
}
println("-----------------------foreach")
arr2.foreach(println)
println("-----------------------")
//不可变数组添加元素(底层创建一个新数组),添加到末尾
val ints = arr2.:+(5)
ints.foreach(println)
println("-----------------------")
val ints1 = arr2.+:(5)
ints1.foreach(println)
println("-----------------------")
//ints1.:+(6) 简化
val ints2 = ints1 :+ 6 //添加到末尾
ints2.foreach(println)
val ints3 = 7 +: ints2 //添加到头部
}
}
- 可变数组
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
object Test_ArrayBuffer {
def main(args: Array[String]): Unit = {
val arr: ArrayBuffer[Int] = new ArrayBuffer[Int]()
//添加元素
val newArr = arr :+ 1 //针对不可变数组
println(arr == newArr)
val newArr1 = arr += 1 //可变数组,引用赋值
println(arr)
println(newArr1)
println(arr == newArr1)
newArr1 += 2
println(newArr1)
println(arr)
3 +=: arr //从前面添加
println(arr)
arr.append(4)
arr.prepend(5)
arr.insert(1, 6)
println(arr)
arr.remove(5) //按照索引删除
println(arr)
arr -= 1 //删除指定元素
println(arr)
//可变数组转换为不可变数组
val array: ArrayBuffer[Int] = ArrayBuffer(11, 22, 33)
val newArray: Array[Int] = array.toArray
println(newArray.mkString(", "))
println(array)
//不可变数组转换成可变数组
val buffer: mutable.Buffer[Int] = newArray.toBuffer
println(buffer)
println(newArray)
}
}
- 二维数组
object Test_MulArray {
def main(args: Array[String]): Unit = {
//创建二维数组
val array1: Array[Array[Int]] = Array.ofDim[Int](2, 3)
array1(0)(2) = 1
array1(1)(0) = 2
for (i <- 0 until array1.length; j <- 0 until array1(i).length){
println(array1(i)(j))
}
for (i <- array1.indices; j <- array1(i).indices){
print(array1(i)(j) + "\t")
if (j == array1(i).length -1) println()
}
array1.foreach(line => line.foreach(println))
array1.foreach(_.foreach(println))
}
}
列表(list)
- 不可变列表
object Test04_List {
def main(args: Array[String]): Unit = {
val list = List(1, 3, 3)
println(list)
println(list(1))
list.foreach(println)
val list2 = 10 +: list
val list3 = list :+ 20
println("-----------------------")
list2.foreach(println)
println("-----------------------")
list3.foreach(println)
val list4 = list.::(88)
println(list4)
println("-----------------------")
val list5 = Nil.::(20)
println(list5)
val list6 = 10 :: 20 :: 30 :: 40 :: Nil
println(list6)
val list7 = list :: list6 //将list直接追加到list6头部
println(list7)
val list8 = list ::: list6 //将list中元素拆分后追加到list6头部
println(list8)
val list9 = list ++ list6 //将list中元素拆分后追加到list6头部
println(list9)
}
}
// 输出结果:
List(1, 3, 3)
3
1
3
3
-----------------------
10
1
3
3
-----------------------
1
3
3
20
List(88, 1, 3, 3)
-----------------------
List(20)
List(10, 20, 30, 40)
List(List(1, 3, 3), 10, 20, 30, 40)
List(1, 3, 3, 10, 20, 30, 40)
List(1, 3, 3, 10, 20, 30, 40)
- 可变列表
import scala.collection.mutable.ListBuffer
object Test05_ListBuffer {
def main(args: Array[String]): Unit = {
val list1: ListBuffer[Int] = new ListBuffer[Int]()
val list2 = ListBuffer(1, 2, 3)
println(list1)
println(list2)
//添加元素
list1.append(12, 4, 5)
list2.prepend(10)
list1.insert(1, 9)
println(list1)
println(list2)
88 +=: list1 += 99
println(list1)
val list3 = list1 ++ list2
println(list3)
list1 ++=: list2 // ++=
println(list1)
println(list2)
list2(3) = 7
println(list2)
list2.remove(2)
list2 -= 99
println(list2)
}
}
集合(set)
- 不可变集合
object Test06_ImmutableSet {
def main(args: Array[String]): Unit = {
val set1 = Set(1, 2, 3, 3)
println(set1)
//添加元素
val set2 = set1 + 20
println(set1)
println(set2)
//合并set
val set3 = Set(12, 55, 3, 88)
val set4 = set1 ++ set3
println(set4)
//删除元素
val set5 = set3 - 12
println(set3)
println(set5)
}
}
- 可变集合
object Test07_MutableSet {
def main(args: Array[String]): Unit = {
//可变集合
val set1: mutable.Set[Int] = mutable.Set[Int](1, 2, 3)
println(set1)
//添加元素
val set2 = set1 + 20
println(set1)
println(set2)
set1 += 30
println(set1)
set1.add(77)
println(set1)
//删除元素
set1 -= 77
println(set1)
set1.remove(3)
println(set1)
println("------------------------")
val set3 = mutable.Set(7, 8, 9)
set1 ++= set3
println(set1)
println(set3)
}
}
Map集合
- 不可变Map
object Test08_ImmutableMap {
def main(args: Array[String]): Unit = {
val map1: Map[String, Int] = Map("a" -> 1, "b" -> 2, "c" ->3)
println(map1)
println(map1.getClass)
map1.foreach(println)
map1.foreach((kv: (String, Int)) => println(kv))
println(map1.get("a").get)
println(map1.getOrElse("d", 0))
println(map1("a"))
}
- 可变Map
object Test09_MutableMap {
def main(args: Array[String]): Unit = {
val map1: mutable.Map[String, Int] = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
println(map1)
println(map1.getClass)
map1.put("d", 4)
println(map1)
map1 += (("e", 5))
println(map1)
//删除
map1.remove("a")
println(map1.getOrElse("a", 0))
map1 -= "b"
println(map1)
map1.update("a", 100)
map1.update("b", 200)
println(map1)
val map2: Map[String, Int] = Map("aa" -> 1, "bb" -> 2, "c" -> 300)
map1 ++= map2
println(map1)
println(map2)
}
}
元组
- 元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据,说的简单点,就是将多个无关的数据封装为一个整体,称为元组。(元组中最大只能有22个元素)
object Test10_Tuple {
def main(args: Array[String]): Unit = {
val tuple: (String, Int, Char, Boolean) = ("hello", 1, 'a', true)
println(tuple)
println(tuple._1)
println(tuple.productElement(1))
println("------------------------")
for (elem <- tuple.productIterator){
println(elem)
}
//嵌套元组
val mulTuple = (12, 0.3, "hello", (23, "scala"), 29)
println(mulTuple._4._2)
}
高级计算函数
- Map类(转换/映射)
object Test11_HightLevelFunction_Map {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
//1.过滤
//选取偶数
val evenList = list.filter((elem: Int) => {elem % 2 == 0})
println(evenList)
//奇数
println(list.filter(_ % 2 == 1))
//map
println(list.map(_ * 2))
println(list.map(x => x * x))
//扁平化
val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
val flatList = nestedList(0) ::: nestedList(1) ::: nestedList(2)
println(flatList)
val flatList2 = nestedList.flatten
println(flatList2)
//扁平映射
//将一组字符串进行分词,并保存成单词的列表
val strings: List[String] = List("hello world", "hello sacla", "hello java", "we study")
val splitList: List[Array[String]] = strings.map(_.split(" ")) //分词
val flattenList = splitList.flatten // 打散扁平化
println(flattenList)
val flatmapList = strings.flatMap(_.split(" "))
println(flatmapList)
//分组groupBy
//分成奇偶两组
val groupMap: Map[Int, List[Int]] = list.groupBy(_ % 2)
val groupMap2: Map[String, List[Int]] = list.groupBy(data => if (data % 2 == 0) "偶数" else "奇数")
println(groupMap)
println(groupMap2)
//给定一组词汇,按照单词的首字母进行分组
val wordList = List("china", "america", "alice", "canada", "cary", "bob", "japan")
println(wordList.groupBy(_.charAt(0)))
}
}
- Reduce类(把集合内的所有数据归约聚合到一个结果)
object Test12_HightLevelFunction_Reduce {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4)
//1. reduce
println(list.reduce(_ + _))
println(list.reduceLeft(_ + _))
println(list.reduceRight(_ + _))
val list2 = List(3, 4, 5, 8, 10)
println(list2.reduce(_ - _))
println(list2.reduceLeft(_ - _))
println(list2.reduceRight(_ - _))
//2.fold(带初始值)
println(list.fold(10)(_ + _)) // 10 + 1 + 2 + 3 + 4
println(list.foldLeft(10)(_ - _)) // 10 - 1 - 2 - 3 - 4
println(list2.foldRight(11)(_ - _)) // 3 - (4 - (5 - (8 - (10 - 11))))
}
}
- 合并Map
object Test_MergeMap {
def main(args: Array[String]): Unit = {
val map1 = Map("a" -> 1, "b"-> 3, "c" -> 6)
val map2 = mutable.Map("a" -> 6, "b"-> 2, "c" -> 9, "d" -> 3)
println(map1 ++ map2)
val map3 = map1.foldLeft(map2)(
(mergedMap, kv) =>{
val key = kv._1
val value = kv._2
mergedMap(key) = mergedMap.getOrElse(key, 0) + value
mergedMap
}
)
println(map3)
}
}
- WordCount(一)
object Test13_CommonWordCount {
def main(args: Array[String]): Unit = {
val stringList: List[String] = List(
"hello",
"hello world",
"hello scala",
"hello spark from scala",
"hello flink from scala"
)
//1. 对字符串进行切分
/*val wordList1: List[Array[String]] = stringList.map(_.split(" "))
val wordList2: List[String] = wordList1.flatten
println(wordList2)*/
val wordList: List[String] = stringList.flatMap(_.split(" "))
println(wordList)
//分组
val groupMap: Map[String, List[String]] = wordList.groupBy(word => word)
println(groupMap)
val countMap: Map[String, Int] = groupMap.map(kv => (kv._1, kv._2.length))
//排序
val sortList: List[(String, Int)] = countMap.toList.sortWith(_._2 > _._2).take(3)
println(sortList)
}
}
- WordCount(二)
object Test14_ComplexWordCount {
def main(args: Array[String]): Unit = {
val tupleList: List[(String, Int)] = List(
("hello", 1),
("hello world", 2),
("hello scala", 3),
("hello spark from scala", 1),
("hello flink from scala", 2)
)
//思路一
val newStringList: List[String] = tupleList.map(kv => {
(kv._1.trim + " ") * kv._2
})
println(newStringList)
val wordCountList: List[(String, Int)] = newStringList.flatMap(_.split(" ")) //空格分词
.groupBy(word => word) //分组
.map(kv => (kv._1, kv._2.length)) //统计单词个数
.toList //map 转 List((), ())
.sortBy(_._2)(Ordering[Int].reverse) //排序
.take(3) //左边取前三
println(wordCountList)
//思路二
val preCountList: List[(String, Int)] = tupleList.flatMap(
tuple =>{
val strings: Array[String] = tuple._1.split(" ")
strings.map(word => (word, tuple._2))
}
)
println(preCountList)
//分组
val preCountMap: Map[String, List[(String, Int)]] = preCountList.groupBy(_._1)
println(preCountMap)
//叠加每个单词预统计的数值
val countMap: Map[String, Int] = preCountMap.mapValues(
tupleList => tupleList.map(_._2).sum
)
println(countMap)
val countList: List[(String, Int)] = countMap.toList.sortWith(_._2 > _._2).take(3)
println(countList)
}
}
队列
import scala.collection.immutable.Queue
import scala.collection.mutable
object Test15_Queue {
def main(args: Array[String]): Unit = {
//可变队列
val queue: mutable.Queue[String] = new mutable.Queue[String]()
queue.enqueue("a", "b", "c", "d")
println(queue)
println(queue.dequeue())
println(queue)
println(queue.dequeue())
println(queue)
queue.enqueue("e", "f")
println(queue)
println(queue.dequeue())
println(queue)
println("----------------------------")
//不可变
val queue2: Queue[String] = Queue("a", "b", "c")
val queue3 = queue2.enqueue("d")
println(queue2)
println(queue3)
}
}
并行执行
import scala.collection.immutable
import scala.collection.parallel.immutable.ParSeq
object Test16_Parallel {
def main(args: Array[String]): Unit = {
val result: immutable.IndexedSeq[Long] = (1 to 100).map(
x => Thread.currentThread.getId
)
println(result)
//并行执行(par)
val result2: ParSeq[Long] = (1 to 100).par.map(
x => Thread.currentThread.getId
)
println(result2)
}
}
模式匹配
object Test01_PatternMatchBase {
def main(args: Array[String]): Unit = {
//基本定义语法
val x: Int = 2
val y: String = x match {
case 1 => "one"
case 2 => "two"
case 3 => "three"
case _ => "other"
}
println(y)
//用模式匹配实现简单的二元运算
val a = 12
val b = 13
def matchDualOp(op: Char): Int = op match {
case '+' => a + b
case '-' => a - b
case '*' => a * b
case '/' => a / b
case '%' => a % b
case _ => -1
}
println(matchDualOp('+'))
println(matchDualOp('\\'))
//模式守卫
//求一个整数的绝对值
def abs(num: Int): Int = {
num match {
case i if i >= 0 => i
case i if i < 0 => -i
}
}
println(abs(1))
println(abs(0))
println(abs(-8))
}
}
object Test02_MatchTypes {
def main(args: Array[String]): Unit = {
//匹配常量
def describeConst(x: Any): String = x match {
case 1 => "Int one"
case "hello" => "String hello"
case true => "Boolean true"
case '+' => "Char +"
case _ => ""
}
println(describeConst("hello"))
//匹配类型
def describeType(x: Any): String = x match {
case i: Int => "Int " + i
case s: String => "String " + s
case list: List[String] => "List " + list
case array: Array[Int] => "Array[Int] " + array.mkString(",")
case a => "Something else: " + a
}
println(describeType(1))
println(describeType(List("a", "b"))) //泛型擦除
println(describeType(List(1, 2)))
println(describeType(Array("2", "21"))) //Array 不存在泛型擦除
//匹配数组
for (arr <- List(
Array(0),
Array(1, 0),
Array(0, 1, 0),
Array(1, 1, 0),
Array(2, 3, 7, 15),
Array("hello", 20, 30)
)) {
val result = arr match {
case Array(0) => "0"
case Array(1, 0) => "Array(1, 0)"
case Array(x, y) => "Array: " + x + "," + y
case Array(0, _*) => "以0开头的数组"
case Array(x, 1, z) => "中间为1的三元素数组"
case _ => "something else"
}
println(result)
}
println("******************************")
//匹配列表
for (list <- List(
List(0),
List(1, 0),
List(0, 0, 0),
List(1, 1, 0),
List(88),
List("hello")
)) {
val result = list match {
case List(0) => "0"
case List(x, y) => "List(x, y)" + x + ", " + y
case List(0, _*) => "List(0, ...)"
case List(a) => "List(a): " + a
case _ => "something else"
}
println(result)
}
//方式二
val list = List(1, 2, 5, 7, 24)
list match {
case first :: second :: rest => println(s"first: $first, second: $second, rest: $rest")
case _ => println("something else")
}
//匹配元组
for (tuple <- List(
(0, 1),
(0, 0),
(0, 1, 0),
(0, 1, 1),
(1, 23, 56),
("hello", true, 0.5)
)) {
val result = tuple match {
case (a, b) => "" + a + ", " + b
case (0, _) => "(0, _)"
case (a, 1, _) => "(a, 1, _):" + a
case (x, y, z) => "(x, y, z): " + x + " " + y + " " + z
case _ => "something else"
}
println(result)
}
}
}
object Test03_MatchTupleExtend {
def main(args: Array[String]): Unit = {
//变量声明时匹配
val (x, y) = (10, "hello")
println(s"x: $x, y: $y")
val List(first, second, _*) = List(23, 15, 9, 78)
println(s"first: $first, second: $second")
val fir :: sec :: rest = List(23, 15, 9, 78)
println(s"fir: $fir, sec: $sec, rest: $rest")
// for 推导式中进行模式匹配
val list: List[(String, Int)] = List(("a", 12), ("b", 35), ("c", 27), ("a", 17))
for (elem <- list) {
println(elem._1 + " " + elem._2)
}
for ((word, count) <- list) {
println(word + " " + count)
}
//只遍历key或者value
for ((word, _) <- list) {
println(word)
}
//指定某个位置的值
for (("a", count) <- list) {
println(count)
}
}
}
object Test04_MatchObject {
def main(args: Array[String]): Unit = {
val student = new Student("alice", 18)
//针对对象实例内容进行匹配
val result = student match {
case Student("alice", 18) => "Alice 18"
case _ => "else"
}
println(result)
}
}
class Student(val name: String, val age: Int)
object Student{
def apply(name: String, age: Int): Student = new Student(name, age)
//实现unapply方法, 用来对对象属性进行拆解
def unapply(student: Student): Option[(String, Int)] = {
if (student == null) {
None
}else {
Some((student.name, student.age))
}
}
}
object Test05_MatchCaseClass {
def main(args: Array[String]): Unit = {
val student = Student1("alice", 18)
//针对对象实例内容进行匹配
val result = student match {
case Student1("alice", 18) => "Alice 18"
case _ => "else"
}
println(result)
}
}
//样例类
case class Student1(name: String, age: Int)
object Test06_PartialFunction {
def main(args: Array[String]): Unit = {
val list: List[(String, Int)] = List(("a", 12), ("b", 35), ("c", 27), ("a", 17))
val newList = list.map(tuple => (tuple._1, tuple._2 * 2))
val newList2 = list.map(
tuple => {
tuple match {
case (word, count) => (word, count * 2)
}
}
)
//省略lambda表达式, 简化(偏函数)
val newList3 = list.map {
case (word, count) => (word, count * 2)
}
println(newList)
println(newList2)
println(newList3)
val positiveAbs: PartialFunction[Int, Int] = {
case x if x > 0 => x
}
val negativeAbs: PartialFunction[Int, Int] = {
case x if x < 0 => -x
}
val zeroAbs: PartialFunction[Int, Int] = {
case 0 => 0
}
def abs(x: Int): Int = (positiveAbs orElse negativeAbs orElse zeroAbs)(x)
println(abs(-1))
println(abs(1))
println(abs(0))
}
}
//异常处理
object Test01_Exception {
def main(args: Array[String]): Unit = {
try{
val n = 10 / 0
}catch {
case e: ArithmeticException => {
println("发送算数异常")
}
case e: Exception => {
println("发生一般异常")
}
}finally {
println("处理结束")
}
}
}
隐式转换(implicit)
- 当编译器第一次编译失败的时候,会在当前环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译。
- 隐式函数::隐式转换可以在不需改任何代码的情况下,扩展某个类的功能
- 隐式参数:普通方法或者函数中的参数可以通过implicit关键字声明为隐式参数,调用改方法时,就可以传入改参数,编译器会在相应的作用域寻找符合条件的隐式值
- 同一个作用域中,相同类型的隐式值只能有一个
- 编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关
- 隐式参数优先于默认参数
- 隐式类:其所带的有参构造参数有且只能有一个,隐式类必须定义在"类"或"伴生对象"或"包对象"里,即隐式类不能是顶级的
- 隐式解析机制:首先会在当前代码作用域下查找隐式实体(隐式方法,隐式类,隐式对象),如果查找失败,会继续在隐式参数的类型的作用域里查找,类型的作用域是指与该类型相关联的全部伴生对象,以及该类型所在包的包对象。
object Test02_Implicit {
def main(args: Array[String]): Unit = {
//隐式函数
implicit def convert(num: Int): MyRichInt = new MyRichInt(num)
//必须在当前作用域内
println(10.myMax(15))
//隐式类
implicit class MyRichInt2(val self: Int) {
def myMax2(n: Int): Int = if(n < self) self else n
def myMin2(n: Int): Int = if(n < self) n else self
}
println(10.myMin2(9))
//隐式参数(柯里化表达),根据类型查找,同一作用域范围内,一个类型的隐式参数只能有一个
implicit val str: String = "张三"
implicit val num: Int = 18
def sayHello()(implicit name: String): Unit = {
println("hello, " + name)
}
def sayHi(implicit name: String): Unit = {
println("hi, " + name)
}
sayHello
sayHi
//简写
def hiAge(): Unit = {
println("hi, " + implicitly[Int])
}
hiAge
}
}
class MyRichInt(val self: Int) {
def myMax(n: Int): Int = if(n < self) self else n
def myMin(n: Int): Int = if(n < self) n else self
}
泛型
- 协变:Son是Father的子类,则MyList[Son]也作为MyList[Father]的子类
- 逆变:Son是Father的子类,则MyList[Son]作为MyList[Father]的父类
- 不变:Son是Father的子类,则MyList[Son]与MyList[Father]无父子关系
object Test03_Generics {
def main(args: Array[String]): Unit = {
//1.协变和逆变
//val childList: MyCollection[Parent] = new MyCollection[Child] //[+E]
val childList: MyCollection[SubChild] = new MyCollection[Child] //[-E]
/**
* 上下限
* [T <: Person]: 泛型上限
* [T >: Person]: 泛型下限
* 上下文限定:
* def f[A : B](a: A) = println(a) 等同于 def f[A](a: A)(implicit arg: B[A]) = println(a)
* @param a
* @tparam A
*/
def test[A <: Child](a: A): Unit = {
println(a.getClass.getName)
}
test[Child](new SubChild)
}
}
//定义继承关系
class Parent {}
class Child extends Parent {}
class SubChild extends Child {}
/**
* 定义带泛型的集合类型
* [+E]: 协变
* [-E]: 逆变
* @tparam E
*/
class MyCollection[-E] {}
完结