0


Scala最基础入门教程

文章目录

一、简介

1、概述

官方编程指南https://www.scala-lang.org/

Scala将面向对象和函数式编程结合成一种简洁的高级语言。

语言特点如下:

(1)Scala和Java一样属于JVM语言,使用时都需要先编译为class字节码文件,并且Scala能够直接调用Java的类库。

(2)Scala支持两种编程范式面向对象和函数式编程。

(3)Scala语言更加简洁高效;语法能够化简,函数式编程的思想使代码结构简洁。

(4)作者马丁·奥德斯基设计Scala借鉴了Java的设计思想,同时优秀的设计也推动了Java语言的发展。

2、Idea环境

  1. 首先确保JDK1.8安装成功
  2. 下载对应的Scala安装文件scala-2.12.10.zip
  3. 解压scala-2.12.10.zip,解压到任意没有中文的路径,例如D:\Tools
  4. 配置Scala的环境变量

新建项目
在这里插入图片描述

添加scala插件
在这里插入图片描述

添加项目支持
在这里插入图片描述

添加Scala安装包
在这里插入图片描述

新建Scala文件夹,并指定为源文件
在这里插入图片描述

新建代码文件
在这里插入图片描述

  1. object HelloWorld {def main(args: Array[String]):Unit={// java的方法调用
  2. System.out.println("hello scala")// scala的方法调用
  3. println("hello scala")}}

二、变量和数据类型

1、注释

基本语法

  1. 基本语法
  2. 1)单行注释://
  3. 2)多行注释:/* */
  4. 3)文档注释:/**
  5. *
  6. */

2、变量和常量(重点)

常量:在程序执行的过程中,其值不会被改变的变量。

1)基本语法

  1. var 变量名 [: 变量类型] = 初始值 var i:Int = 10
  2. val 常量名 [: 常量类型] = 初始值 val j:Int = 20

注意:能用常量的地方不用变量。

特征:

  • 声明变量时,类型可以省略,编译器自动推导,即类型推导。
  • 类型确定后,就不能修改,说明Scala是强数据类型语言。
  • 变量声明时,必须要有初始值。
  • 在声明/定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改。
  • var修饰的对象引用可以改变,val修饰的对象则不可改变,但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)。

3、标识符的命名规范

  • 以字母或者下划线开头,后接字母、数字、下划线
  • 以操作符开头,且只包含操作符(+ - * / # !等)
  • 用反引号....包括的任意字符串,即使是Scala关键字(39个)也可以

4、关键字(39)

  • package, import, class, object, trait, extends, with, type, for
  • private, protected, abstract, sealed, final, implicit, lazy, override
  • try, catch, finally, throw
  • if, else, match, case, do, while, for, return, yield
  • def, val, var
  • this, super
  • new
  • true, false, null

5、字符串输出

1、字符串,通过+号拼接

  1. // 1、字符串,通过+号拼接
  2. System.out.println()
  3. println("hello"+"world")

2、重复字符串拼接

  1. // 2、重复字符串拼接
  2. println("lilei "*20)

3、printf用法:字符串,通过%传值

  1. // 3、printf用法:字符串,通过%传值
  2. printf("name:%s age %d\n","linlai",8)

4、字符串模板(插值字符串):通过$获取变量值

  1. s""

:标明当前是需要取值计算的字符串

  1. $name

:取变量

  1. name

值,赋值到字符串中。

  1. ${age+1}

:取变量

  1. age

值,并进行计算+1.

  1. // 4、字符串模板(插值字符串):通过$获取变量值val name ="linhai"val age =8val s1 =s"name:$name,age:${age}"
  2. println(s1)val s2 =s"name:${name +1},age:${age +2}"
  3. println(s2)

5、多行字符串

  1. // 5、多行字符串
  2. println("我"+"是"+"中国人")
  3. println("""我
  4. |是
  5. |中国
  6. |人
  7. |""".stripMargin)val margin ="""
  8. |我
  9. |是
  10. |中国人
  11. |""".stripMargin

6、数据类型

在这里插入图片描述

6.1 整数类型(Byte、Short、Int、Long)

数据类型****描述Byte [1]8位有符号补码整数。数值区间为 -128 到 127Short [2]16位有符号补码整数。数值区间为 -32768 到 32767Int [4]32位有符号补码整数。数值区间为 -2147483648 到 2147483647Long [8]64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 = 2的(64-1)次方-1

  1. val a1:Byte=1val a2:Short=2val a3:Int=3val a4:Long=4
6.2 浮点类型(Float、Double)

数据类型****描述Float [4]32 位, IEEE 754标准的单精度浮点数Double [8]64 位 IEEE 754标准的双精度浮点数

  1. val b1:Double=3.14// 默认为Double类型
  2. val b2 =3.14
  3. val b3:Float=3.14f
6.3 字符类型(Char)

字符类型可以表示单个字符,字符类型是Char。

  1. val c1:Char='a'val c2:Char=523val c3:Char='\t'val c4:Char='\n'val c5:Char='\\'val c6 ='\"'
6.4 布尔类型(Boolean)
  • 布尔类型也叫Boolean类型,Booolean类型数据只允许取值true和false
  • boolean类型占1个字节。
  1. val bo1:Boolean=trueval bo2:Boolean=false
6.5 Unit类型、Null类型和Nothing类型(重点)

数据类型描述Unit表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。Nullnull , Null 类型只有一个实例值nullNothingNothing类型在Scala的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性)

  • Unit类型用来标识过程,也就是没有明确返回值的函数,就算是有值也不接收数值。
  1. val u1:Unit={10
  2. println(10)}
  3. println(u1)// 如果标记对象的类型是unit的话 后面有返回值也没法接收// unit虽然是数值类型 但是可以接收引用数据类型 因为都是表示不接收返回值val u2:Unit=10
  4. println(u2)

打印结果:

  1. 10
  2. ()
  3. ()
  • Null类只有一个实例对象,Null类似于Java中的null引用。Null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)。
  1. var n2:String="bb"
  2. n2 ="cc"
  3. n2 =null// 值类型不能等于null,idea不会识别报错 编译器会报错var i4 =10// i4 = null
  • Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。
  1. // 可以用来抛出异常// 可以接收任意数据类型(Int使用Nothing接收)val value:Nothing={
  2. println("hello")1+1thrownew RuntimeException()}

7、类型转换

7.1 数值类型自动转换

当Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:

在这里插入图片描述

  • 自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
  • 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
  • (byte,short)和char之间不会相互自动转换。
  • byte,short,char他们三者可以计算,在计算时首先转换为int类型。
  1. // 自动类型提升,以最大的类型进行结果存储val f1:Float=1+1L+3.14fval f2:Double=1+1L+3.14val f3:Double=1+1L+3.14f+3.14// 把精度大的赋值给精度小的会报错,反之会进行类型转换val i =10val b:Double= i
  2. // (byte、short、char)之间不会相互转换val b1:Byte=10val c1:Char=20// byte,short,char他们三者可以计算,在计算时首先转换为int类型。val b2:Byte=20val i1:Int= b1 + b2
7.2 强制类型转换

自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。

  1. Java : int num =(int)2.5
  2. Scala :var num :Int=2.7.toInt
  1. // 1、将高精度转为低精度,就需要使用强制转换val int =2.99.toInt
  2. val int1 =(10*3.5+6*1.5).toInt
7.3 数值类型与String类型间转换
  • 基本类型转String类型(语法:将基本类型的值+“” 即可)。
  • String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)。
  1. // 1、基本类型转为String类型val str =1+""// 2、string类型转为数值类型val d1 ="3.14".toDouble
  2. val d2 ="1".toInt
  3. // 3、小数类型,需先转为Double再转为Int类型val i1 ="3.14".toDouble.toInt
  4. // 标记为f的float数能够识别val i02 ="12.5f".toFloat

三、运算符

1、算数运算符

运算符运算范例结果+正号+33-负号b=4; -b-4+加5+510-减6-42乘3412/除5/51%取模(取余)7%52+字符串相加“He”+”llo”“Hello”

2、关系运算符

运算符运算范例结果==相等于4==3false!=不等于4!=3true<小于4<3false>大于4>3true<=小于等于4<=3false>=大于等于4>=3true

  1. // ==比较两个变量本身的值,即两个对象在内存中的首地址;// equals比较字符串中所包含的内容是否相同。
  2. println("a".equals("b"))
  3. println("a"=="b")

3、逻辑运算符

运算符描述实例&&逻辑与(A && B) 运算结果为 false||逻辑或(A || B) 运算结果为 true!逻辑非!(A && B) 运算结果为 true

4、赋值运算符

运算符描述实例=简单的赋值运算符,将一个表达式的值赋给一个左值C = A + B 将 A + B 表达式结果赋值给 C+=相加后再赋值C += A 等于 C = C + A-=相减后再赋值C -= A 等于 C = C - A*=相乘后再赋值C *= A 等于 C = C * A/=相除后再赋值C /= A 等于 C = C / A%=求余后再赋值C %= A 等于 C = C % A<<=左移后赋值C <<= 2等于 C = C << 2>>=右移后赋值C >>= 2 等于 C = C >> 2&=按位与后赋值C &= 2 等于 C = C & 2^=按位异或后赋值C ^= 2 等于 C = C ^ 2|=按位或后赋值C |= 2 等于 C = C | 2

5、位运算符

运算符描述实例&按位与运算符(a & b) 输出结果 12 ,二进制解释: 0000 1100|按位或运算符(a | b) 输出结果 61 ,二进制解释: 0011 1101^按位异或运算符(a ^ b) 输出结果 49 ,二进制解释: 0011 0001按位取反运算符(a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。<<左移动运算符a << 2 输出结果 240 ,二进制解释: 0011 0000>>右移动运算符a >> 2 输出结果 15 ,二进制解释: 0000 1111>>>无符号右移a >>>2 输出结果 15, 二进制解释: 0000 1111

  1. var a:Int=1000// 4000
  2. println(a <<2)// 250
  3. println(a >>2)

6、Scala运算符本质

在Scala中其实是没有运算符的,所有运算符都是方法。

  • 当调用对象的方法时,点.可以省略。
  • 如果函数参数只有一个,或者没有参数,()可以省略。
  1. var nu1:Int=1.+(1)val nu2:Int=1+(1)val nu3:Int=1+1

四、流程控制

1、分支控制(if-else)

让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支。

  1. // 1、简单If-elseif(age <18){
  2. println("童年")}elseif(age >18&& age <60){
  3. println("中年")}else{
  4. println("老年")}// 2、使用方法计算val result:String={if(age <18){"童年"}else{"老年"}}
  5. println(result)// 3、不确定返回值类型。使用Any代替val res:Any={if(age >18){"童年"}else{100}}
  6. println(res)// 4、三元运算符使用val res01:Any=if(age >18)"童年"else"中年"
  7. println(res01)

2、For循环控制

  1. for(i <-0 to 5){
  2. println(i)}for(i <-0 until 5){
  3. println(i)}for(i <-0 to 5){if(i >1){
  4. print(i)}}for(i <-0 to 5if i >2){
  5. print(i)}// (10, 10, 10, 10)val ints: immutable.IndexedSeq[Int]=for(i <-0 to 3)yield{10}

3、while和do…while循环

  1. var i =0// while循环while(i <5){
  2. println(i)
  3. i += i
  4. }// do-while循环do{
  5. println(i)
  6. i += i
  7. }while(i <5)
4、循环中断

Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数式编程,推荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable控制结构来实现break和continue功能。

  1. // 1、采用异常的方式退出循环try{for(e <-1 to 5){
  2. println(e)if(e >4){thrownew Exception()}}}catch{case e: Throwable =>}// 2、采用Scala自带的函数,退出循环
  3. Breaks.breakable(for(e <-1 to 5){
  4. println(e)if(e >4){
  5. Breaks.break()}})// 3、对break进行省略
  6. breakable {for(e <-1 to 10){if(e >9){
  7. break
  8. }}}

四、函数式编程

  • 面向对象编程 解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题。 对象:用户; 行为:登录、连接jdbc、读取数据库 属性:用户名、密码 Scala语言是一个完全面向对象编程语言。万物皆对象
  • 函数式编程 解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的步骤,解决问题。 例如:请求->用户名、密码->连接jdbc->读取数据库 Scala语言是一个完全函数式编程语言。万物皆函数

1、方法定义

在这里插入图片描述

  1. object Hello {def main(args: Array[String]):Unit={// 自定义方法:f:方法名。arg:参数名。String:参数类型。Unit:返回值空def f(arg:String):Unit={
  2. println(arg)}// 调用方法
  3. f("hello world")}}
  • 方法1:无参,无返回值
  • 方法2:无参,有返回值
  • 方法3:有参,无返回值
  • 方法4:有参,有返回值
  • 方法5:多参,无返回值
  1. // 有参。有返回值def f1(arg:String):String={
  2. arg +" world"}
  3. println(f1("hello"))// 有参。无返回值def f2(args:String):Unit={
  4. println(args)}
  5. println(f2("hello"))// 无参。有返回值def f3():String={"hello world"}
  6. println(f3())// 无参。无返回值def f4():Unit={
  7. println("hello world")}
  8. f4()// 多参。无返回值def f5(args01:String, args02:String):Unit={
  9. args01 + args02
  10. }
  11. f5("hello","world")

方法至简原则

  • return可以省略,Scala会使用方法体的最后一行代码作为返回值
  • 如果方法体只有一行代码,可以省略花括号
  • 返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)特别注意事项:
  • 如果有return,则不能省略返回值类型,必须指定
  • 如果方法明确声明unit,那么即使方法体中使用return关键字也不起作用
  • Scala如果期望是无返回值类型,可以省略等号(=号和方法体大括号不能同时省略)
  • 如果方法无参,但是声明了参数列表,那么调用时,小括号,可加可不加(声明无括号调用时也没有括号)
  • 如果方法没有参数列表,那么小括号可以省略,调用时小括号必须省略
  1. // 1、return可以省略,Scala会使用方法体的最后一行代码作为返回值def s1():String={"hello01""hello02"}// 2、如果方法体只有一行代码,可以省略花括号def s2():Int=1+2// 3、返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)特别注意事项:def s3()=1+2// 4、如果有return,则不能省略返回值类型,必须指定def s4():Int={return1+2}// 5、如果方法明确声明unit,那么即使方法体中使用return关键字也不起作用def s5():Unit={return1+2}// 6、Scala如果期望是无返回值类型,可以省略等号(=号和方法体大括号不能同时省略)def s6(){
  2. println(1+1)}// 7、如果方法无参,但是声明了参数列表,那么调用时,小括号,可加可不加(声明无括号调用时也没有括号)def s7():Unit={
  3. println(1+2)}
  4. s7()
  5. s7
  6. // 8、如果方法没有参数列表,那么小括号可以省略,调用时小括号必须省略def s8 {
  7. println("hello")}
  8. s8

2、可变参数

  • 可变参数:本质是1个数组
  • 参数位置:如果参数列表中存在多个参数,那么可变参数一般放置在最后,(不能和默认值一起用,和带名参数用时,不能改变带名参数的顺序)
  • 参数默认值:一般将有默认值的参数放置在参数列表的后面
  1. // 1、可变参数。本质是1个数组def sayHi(name:String*):Unit={
  2. println(s"hi $name")for(e <- name){
  3. println(name)}}
  4. sayHi("hello01","hello02","hell03")// 2、可变参数必须要放在参数列表最后def sayHi2(age:Int, name:String*):Unit={
  5. println(s"hi $name")}
  6. sayHi2(18,"hello01","hello02")// 3、参数默认值def sayHi3(age:Int, name:String="张三"):Unit={
  7. println(s"hi $age$name")}// hi 18 张三
  8. sayHi3(18)// 4、默认值参数在使用的时候,可以不在最后def say4(name:String="张三", age:Int):Unit={
  9. println(s"hi $age$name")}
  10. sayHi3(18)

3、函数

函数的返回值就是函数体中最后一个表达式的结果值/return语句的返回值。

在这里插入图片描述

函数和方法的区别

  • 方法定义在类中可以实现重载,函数不可以重载。
  • 方法是保存在方法区,函数是保存在堆中。
  • 定义在方法中的方法可以称之为函数,不可以重载。
  • 方法可以转成函数, 转换语法: 方法名 _。
  1. // 不支持重载val test =()=>{
  2. println("无参")}
  3. test()// val test =(name:String)=>{// println("构造")// }// 3、函数可以嵌套val test02 =()=>{val test03 =()=>{
  4. println("无参+构造")}
  5. println("无参")}
  6. test02()// 4、方法可以转为函数def add():Unit={
  7. println("方法")}val add2 = add _

4、高阶函数

参数/返回值为函数的方法/函数称为高阶函数

  1. // 函数ope作为参数传入,def cal(a:Int, b:Int, ope:(Int,Int)=>Int):Int={
  2. ope(a, b)}// 函数求和def plus(x:Int, y:Int):Int={
  3. x + y
  4. }
  5. println(cal(1,3, plus))

5、匿名函数

没有名字的函数/方法就是匿名函数。

(x:Int)=>{函数体}

x:表示输入参数名称;Int:表示输入参数类型;函数体:表示具体代码逻辑

  • 参数的类型可以省略,会根据形参进行自动的推导
  • 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号。
  • 匿名函数如果只有一行,则大括号也可以省略
  • 如果参数只出现一次,且按照顺序出现则参数省略且后面参数可以用_代替
  1. val f0:(Int,Int)=>Int=(x:Int, y:Int)=> x + y
  2. // 1、参数的类型可以省略,会根据形参自动推导val f1:(Int,Int)=>Int=(x, y)=> x + y
  3. //2、类型省略后,发现只有1个参数,则圆括号可以省略val f2:(Int,Int)=>Int=(x, y)=> x + y
  4. val f3:Int=>Int= x => x +22val f4:()=>Int=()=>22// 3、匿名函数如果只有一行,则大括号也可以省略val f5:(Int,Int)=>Int=(x, y)=>{
  5. x + y
  6. }val f6:(Int,Int)=>Int=(x, y)=> x + y
  7. // 4、如果参数只出现一次,且按照顺序出现,则参数省略且后面的参数可以用_代替val f7:(Int,Int)=>Int= _ + _

不能化简为下划线的情况: 1.化简之后只有一个下划线 2.化简后的函数存在嵌套

  1. // 1、传入的参数类型可以推断 所以可以省略val f8:(Int,Int)=>Int=(x, y)=> y - x
  2. val f8_1:(Int,Int)=>Int= _ - _
  3. // 2、参数必须只使用一次,使用的顺序必要和定义的顺序一直val f9:(Int,Int)=>Int=-_ + _

6、函数柯里化&闭包

函数柯里化:将一个接收多个参数的函数转化成一个接受一个参数的函数过程,可以简单的理解为一种特殊的参数列表声明方式。
闭包:就是一个函数和与其相关的引用环境(变量)组合的一个整体(实体)

  1. // 外部参数var z:Int=10// 闭包def f(y:Int):Int={
  2. z + y
  3. }

1

  1. // 原样val sum =(x:Int, y:Int, z:Int)=> x + y + z
  2. sum(1,2,3)// 1、val sum1 =(x:Int)=>{
  3. y:Int=>{
  4. z:Int=>{
  5. x + y + z
  6. }}}
  7. sum1(1)(2)(3)// 2、第二种val sum2 =(x:Int)=>(y:Int)=>(z:Int)=> x + y + z
  8. sum2(1)(2)(3)// 3、第三种def sum3(x:Int)(y:Int)(z:Int)= x + y + z
  9. sum3(1)(2)(3)

7、递归

一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用

  1. def main(args: Array[String]):Unit={
  2. println(test(5))}// 递归方法(test方法)def test(i:Int):Int={if(i ==1){1}else{
  3. i * test(i -1)}}

五、面向对象

1、定义

  • Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)。
  • 一个Scala源文件可以包含多个类。

基本语法

  1. [修饰符]class 类名 {
  2. 类体
  3. }
  1. packagecom.atguigu.chapter06//(1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)class Person {}//(2)一个Scala源文件可以包含多个类class Teacher{}

2、属性和封装

  1. class Person {@BeanPropertyvar age:Int= _
  2. // val只能生成get方法@BeanPropertyval name:String="张三"}

测试类

  1. object Test {def main(args: Array[String]):Unit={val person =new Person
  2. person.age =18
  3. person.setAge(18)
  4. println(person.getName)}}

3、访问权限

  • Scala 中属性和方法的默认访问权限为public,但Scala中无public关键字。
  • private为私有权限,只在类的内部和伴生对象中可用。
  • protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。
  • private[包名]增加包访问权限,包名下的其他类也可以使用

4、方法

  1. def 方法名(参数列表)[:返回值类型]={
  2. 方法体
  3. }

案例

  1. class Person {def sum(n1:Int, n2:Int):Int={
  2. n1 + n2
  3. }}object Test01 {def main(args: Array[String]):Unit={val test: Test01 =new Test01()
  4. println(test.sum(1,2))}}

5、构造器

和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。

Scala类的构造器包括:主构造器和辅助构造器

  1. class 类名(形参列表){// 主构造器// 类体defthis(形参列表){// 辅助构造器}defthis(形参列表){//辅助构造器可以有多个...}}

案例:

  1. // 主构造器class Person01(name:String){val name1:String= name
  2. var age:Int= _
  3. // 辅助构造器01defthis()={this("张三")}// 复制构造器02defthis(name:String, age1:Int)={this()this.age = age1
  4. }}

测试类

  1. object Test {def main(args: Array[String]):Unit={val person01: Person01 =new Person01()val person02: Person01 =new Person01("张三")val person03: Person01 =new Person01("张三",18)}}

6、构造器参数

Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰

  • 未用任何修饰符修饰:这个参数就是一个局部变量,底层有属性的特性。
  • var修饰参数:作为类的成员属性使用,可以修改。
  • val修饰参数:作为类只读属性使用,不能修改。
  1. // 主构造器参数 分为3类:// 没有修饰符: 作为构造方法中的传入参数使用// val 修饰: 会自动生产同名的属性 并且定义为val// var 修饰 : 会自动生产同名的属性 并且定义为varclass Person02(name1:String,var age1:Int,val sex1:Int){val name:String= name1
  2. }// 等效方法class Person02(name1:String, age1:Int,sex1 :Int){val name:String= name1
  3. val age:Int= age1
  4. val sex:Int= sex1
  5. }

7、scala的object

java中存在静态属性、静态方法、非静态属性、非静态方法。

  • scala当中不存在静态与非静态。object中定义的所有属性与方法、函数,除开private修饰的,都可以通过对象名.属性、对象名.方法、对象名.函数 的方式调用,可以理解为java中的static修饰的。
  • Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明。
  1. object TestObject {val name:String="zhansan"var age:Int=30privateval address:String="深圳"def getName():String={this.name +" "+this.name
  2. }val func =(x:Int, y:Int)=>{
  3. x * y
  4. }}
  1. object Test102 {def main(args: Array[String]):Unit={// object中的属性直接通过 类名.属性名 方式调用(zhansan)
  2. println(TestObject.name)// 30
  3. println(TestObject.age)// 设置属性
  4. TestObject.age =66// 66
  5. println(TestObject.age)
  6. println("====")// object中的方法直接通过 类名.方法名 方式调用(zhansan zhansan)
  7. println(TestObject.getName())// object中的方法直接通过 类名.函数名 方式调用(6)
  8. println(TestObject.func(2,3))}}

8、伴生类与伴生对象

  • 如果有一个class,另外还有一个object,并且二者同名。
  • class与object在同一个文件中。

如果满足上两个条件,那么就称这个object为class的伴生对象,称class为object的伴生类。

  • 伴生类与伴生对象可以互相访问对方的私有成员。
  • 伴生类可以互相访问private修饰的值,但是在外部不能够访问。
  1. class ClassObjectTest {val name:String="lisi"//用private修饰的只能在类或者伴生对象中使用privateval age =20//此时可以调用伴生对象中用private修饰的 address属性def getAddress()= ClassObjectTest.address
  2. }object ClassObjectTest{privateval address ="shenzhen"def getName()={//创建伴生类的对象val obj =new ClassObjectTest()//此时可以调用伴生类中用private修饰的name属性
  3. obj.name
  4. }}

9、apply方法

  • 通过伴生对象的apply方法,实现不使用new方法创建对象。
  • 如果想让主构造器变成私有的,可以在()之前加上private。
  • apply方法可以重载。
  • Scala中obj(arg)的语句实际是在调用该对象的apply方法,即obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
  • 当使用new关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时伴生对象的apply方法。
  1. object Test11_Apply {def main(args: Array[String]):Unit={// 如果调用的方法是apply的话 方法名apply可以不写val one: Person11 = Person11()// 类的apply方法调用(打印类方法)
  2. one()}}class Person11 private(){var name:String= _
  3. defthis(name:String){this()this.name = name
  4. }def apply():Unit= println("类的apply方法调用")}object Person11 {// 使用伴生对象的方法来获取对象实例def getPerson11: Person11 =new Person11
  5. // 伴生对象的apply方法def apply(): Person11 =new Person11()// apply方法的重载def apply(name:String): Person11 =new Person11(name)}}

10、类型检查和转换

  1. // 判断obj是不是T类型。
  2. obj.isInstanceOf[T]// 将obj强转成T类型。
  3. obj.asInstanceOf[T]// 获取类模板。
  4. classOf
  1. // 判断person类型是不是为Teacherif(person1.isInstanceOf[Teacher]){// 假如类型为Teacher,则强转为Teacherval teacher1: Teacher = person1.asInstanceOf[Teacher]
  2. teacher1.sayHi1()}// 调用固定的方法 返回类模板val value: Class[Student15]= classOf[Student15]

六、集合

1、简介

  • Scala的集合有三大类:序列Seq(List)、集Set、映射Map,所有的集合都扩展自Iterable特质。
  • 对于几乎所有的集合类,Scala都同时提供了可变不可变的版本,分别位于以下两个包。- 不可变集合:scala.collection.immutable- 可变集合: scala.collection.mutable
  • Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于java中的String对象。
  • 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于java中StringBuilder对象。

建议:在操作集合的时候,不可变用符号,可变用方法。

不可变集合

在这里插入图片描述

  • Set、Map是Java中也有的集合。
  • Seq是Java没有的,我们发现List归属到Seq了,因此这里的List就和Java不是同一个概念了。.
  • 我们前面的for循环有一个 1 to 3,就是IndexedSeq下的Range。
  • String也是属于IndexedSeq。
  • 我们发现经典的数据结构比如Queue和Stack被归属到LinearSeq(线性序列)。
  • 大家注意Scala中的Map体系有一个SortedMap,说明Scala的Map可以支持排序。
  • IndexedSeq和LinearSeq的区别。 - IndexedSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位。- LinearSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找。

可变集合

在这里插入图片描述

2、数组

2.1 不可变数组
  1. val arr1 =new Array[Int](10)
  • new是关键字。
  • [Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any。
  • (10),表示数组的大小,确定后就不可以变化。
  1. object Test01 {def main(args: Array[String]):Unit={// 创建不可变数组val ints =new Array[Int](10)// 可以使用伴生对象的apply方法val array01: Array[Int]= Array(1,2,3,4,5)// 遍历数组(print打印)
  2. println(array01.toList)// 遍历数组(遍历)for(e <- array01){
  3. println(e)}// 遍历数组(迭代器)val iterator: Iterator[Int]= array01.iterator
  4. while(iterator.hasNext){
  5. println(iterator.next())}// 遍历数组(匿名函数)
  6. array01.foreach(e => println(e))// 遍历数组(使用系统函数)
  7. array01.foreach(println)// 修改数组值
  8. array01(0)=10
  9. println(array01(0))// 添加元素,生成新数组array02、原数组array01不变val array02: Array[Int]= array01 :+1}}
2.2 可变数组

定义:

  • [Any]存放任意数据类型。
  • (3, 2, 5)初始化好的三个元素。
  • ArrayBuffer需要引入scala.collection.mutable.ArrayBuffer
  1. val array: ArrayBuffer[Int]= ArrayBuffer(1,2,3)

ArrayBuffer是有序的集合。

增加元素使用的是append方法(),支持可变参数。

  1. // 创建可变数组val array: ArrayBuffer[Int]=new ArrayBuffer[Int]()val arrayBuffer02: ArrayBuffer[Int]= ArrayBuffer(1,2,3,4)// 向可变数组中添加元素
  2. array.append(10)
  3. array.appendAll(Array(1,2,3,4))// 循环打印
  4. array.foreach(println)
  5. println(array)// 更新元素值
  6. array.update(0,100)
  7. array(1)=200
  8. println(array)
  9. println(array(0))// 删除元素
  10. array.remove(0)
  11. array.remove(1,3)
2.3 不可变数组与可变数组的转换
  • arr2.toArray返回结果才是一个不可变数组,arr2本身没有变化。
  • arr1.toBuffer返回结果才是一个可变数组,arr1本身没有变化。
  1. // 不可变数组转可变数组
  2. arr1.toBuffer
  3. // 不可变数组转可变数组
  4. arr2.toArray
  1. // 不可变数组val array: Array[Int]= Array(1,2,3,4)// 可变数组val arrayBuffer: ArrayBuffer[Int]= ArrayBuffer(5,6,7,8)// 添加元素(不可变数组)val arra01: Array[Int]= array :+1
  2. arrayBuffer.append(1)// 可变 => 不可变val array01: Array[Int]= arrayBuffer.toArray
  3. // 不可变 => 可变val buffer: mutable.Buffer[Int]= array.toBuffer
  4. val arrayBuffer01: ArrayBuffer[Int]= buffer.asInstanceOf[ArrayBuffer[Int]]
2.4 多维数组
  • 二维数组中有三个一维数组,每个一维数组中有四个元素。
  1. // 3行4列val array02: Array[Array[Double]]= Array.ofDim[Double](3,4)
  1. val arrayDim: Array[Array[Double]]= Array.ofDim[Double](3,4)// 赋值
  2. arrayDim(0)= Array(1,2,3,4)
  3. arrayDim(0)(1)=100// 遍历for(array <- arrayDim){for(elem <- array){
  4. print(elem +" ")}}

3、Seq集合(List)

不可变List

  1. // 创建集合(List)val list01: List[Any]= List(1,1,1,1.0,"hello",'c')val list02: List[Int]= List(1,2,3,4)// 遍历集合
  2. list01.foreach(println)// 增加数据(末尾增加)val list011: List[Any]= list01 :+1// 增加数据(开头增加)val list012: List[Any]=2:: list011
  3. // 合并2个集合(1个集合插入另1个集合中)(List(List(1, 1, 1, 1.0, hello, c), 1, 2, 3, 4))val list013: List[Any]= list01 :: list02
  4. // 合并2个集合(1个集合元素遍历插入另1集合)(List(1, 1, 1, 1.0, hello, c, 1, 2, 3, 4))
  5. println(list01 ::: list02)// 取值val value:Int= list02(2)// 空集合Nil(List(1, 2, 3, 4))val ints: List[Int]=1::2::3::4:: Nil

可变ListBuffer

  1. // 可变List创建(ListBuffer())val listBuffer: ListBuffer[Int]=new ListBuffer[Int]()// ListBuffer(1, 2, 3, 4)val listBuffer1: ListBuffer[Int]= ListBuffer(1,2,3,4)// 添加元素(末尾头)(ListBuffer(5))
  2. listBuffer.append(5)// 添加元素(开头)(ListBuffer(0, 5))
  3. listBuffer.prepend(0)// 删除元素(ListBuffer(5))
  4. listBuffer.remove(0)// 更新值(ListBuffer(5))
  5. listBuffer(0)=1

4、Set集合

默认情况下,Scala使用的是不可变集合,如果你想使用可变集合,需要引用

  1. scala.collection.mutable.Set

包。

不可变集合

  • Set默认是不可变集合。
  • 数据无序不可重复。
  • 默认使用hash set
  1. val set: Set[Int]= Set(3,2,4,1)// set的特点 无序不可重复
  2. println(set)// 不可变使用符号(无变化s)(Set(3, 2, 4, 1))val set2: Set[Int]= set +1
  3. println(set)
  4. println(set2)// 作用 判断集合是否包含某个元素(true)val bool:Boolean= set.contains(2)
  5. println(bool)

**可变集合

  1. mutable.Set

**

  1. // 创建可变Set(Set(1, 5, 2, 3, 4))val set: mutable.Set[Int]= mutable.Set(1,2,3,4,5)// 添加数据(1, 5, 2, 3, 4)val bool:Boolean= set.add(5)// 遍历
  2. set.foreach(println)// 删除元素(Set(1, 5, 3, 4))val bool1:Boolean= set.remove(2)
  3. println(set)

5、Map集合

Scala中的Map和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射。

不可变Map

  1. // 1、创建不可变Mapval map: Map[String,Int]= Map("hello"->100,"world"->200)val map02: Map[String,Int]= Map(("hello",100),("world",200))// 2、遍历打印for(elem <- map){
  2. println(elem)}// 遍历打印(foreach打印)
  3. map.foreach(print)// 遍历打印(打印key)val keys: Iterable[String]= map.keys
  4. keys.foreach(print)// 遍历打印(打印value)val values: Iterable[Int]= map.values
  5. // 遍历打印(直接打印)
  6. println(map)// 3-1、获取value的值(Option)val option: Option[Int]= map.get("hello")// 根据Option取值(option.isDefined/option.isEmpty)if(!option.isEmpty){
  7. println(option.get)}
  8. println(option.getOrElse(1))// 3-1、获取value的值(getOrElse)val map01: Map[Int,String]= Map((1,"4324"))// 不确定存在val str1:String= map01.getOrElse(1,"4324")// 按key取值val str:String= map01(1)

可变Map

  1. // 创建可变mapval map: mutable.Map[String,Int]= mutable.Map(("a",1),("b",1),("c",2),("d",4))
  2. println(map)// 添加元素
  3. map.put("z",10)
  4. println(map)// 修改元素值
  5. map.update("b",20)
  6. map("a")=30// 删除元素
  7. map.remove("a")

6、元组

  • 元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组。
  • 注意:元组中最大只能有22个元素。
  1. // 1、声明元组val tuple:(Int,String,Boolean)=(40,"bobo",true)// 2-1、访问元组(单个)
  2. println(tuple._1)// 2-2、访问元组(单个)val value:Any= tuple.productElement(0)
  3. println(value)// 2-3、访问元组(迭代器遍历)for(elem <- tuple.productIterator){
  4. println(elem)}// 3、Map中使用(以元组方式初始化Map)val map: Map[String,Int]= Map("a"->1,"b"->2,"c"->3)val map02: Map[String,Int]= Map(("a",1),("b",2),("c",3))

7、集合常用函数

7.1 基本操作
  • 获取集合长度
  • 获取集合大小
  • 循环遍历
  • 迭代器
  • 生成字符串
  • 是否包含
  1. val list: List[Int]= List(1,2,3,4,5,6)// 获取集合长度
  2. println(list.length)// 获取集合的大小(size=length)
  3. println(list.size)// 循环遍历
  4. list.foreach(println)// 迭代器for(elem <- list.iterator){
  5. println(elem)}// 按规定字符串(1,2,3,4,5,6)
  6. println(list.mkString(","))// 是否包含(true)
  7. println(list.contains(3))
7.2 衍生集合
  • 获取集合的头
  • 获取集合的尾(不是头的就是尾)
  • 集合最后一个数据
  • 集合初始数据(不包含最后一个)
  • 反转
  • 取前(后)n个元素
  • 去掉前(后)n个元素
  • 并集
  • 交集
  • 差集
  • 拉链
  • 滑窗
  1. val list: List[Int]= List(1,2,3)val list02: List[Int]= List(3,4,5)// 获取集合的头(1)
  2. println(list.head)// 获取集合最后1个元素(3)
  3. println(list.last)// 集合头数据(不包含最后1个)(List(1, 2))
  4. println(list.init)// 获取集合的尾(不包含第1个)(List(2, 3))
  5. println(list.tail)// 反转(List(3, 2, 1))
  6. println(list.reverse)// 取前(后)n个元素
  7. println(list.take(2))
  8. println(list.takeRight(2))// 去掉前(后)n个元素(List(3))(List(1))
  9. println(list.drop(2))
  10. println(list.dropRight(2))// 并集(List(1, 2, 3, 4, 5))
  11. println(list.union(list02))// 交集(List(3))
  12. println(list.intersect(list02))// 差集(List(1, 2))
  13. println(list.diff(list02))// 拉链(List((1,3), (2,4), (3,5)))
  14. println(list.zip(list02))// 划窗(List(1, 2))
  15. list.sliding(2,5).foreach(println)
7.3 集合计算初级函数
  • 求和
  • 求乘积
  • 最大值
  • 最小值
  • 排序 - sorted:对一个集合进行自然排序,通过传递隐式的Ordering。- sortBy:对一个属性或多个属性进行排序,通过它的类型。- sortWith:基于函数的排序,通过一个comparator函数,实现自定义排序的逻辑。
  1. val list: List[Int]= List(1,5,-3,4,2,-7,6)val list1: ListBuffer[Int]= ListBuffer(1,5,-3,4,2,-7,6)// 1、求和
  2. println(list.sum)// 2、求乘积
  3. println(list.product)// 3、最大值
  4. println(list.max)// 4、最小值
  5. println(list.min)// 5-1、排序(默认)(从小到大)
  6. println(list.sorted)// 排序(从大到小)
  7. println(list.sorted(Ordering[Int].reverse))// 5-2、排序(元组)val tuples: List[(String,Int)]= List(("hello",10),("world",12),("scala",9))// 排序(元组)(默认字典序)
  8. println(tuples.sorted)// 排序(元组)(第2个元素从小到大排序)val tuples1: List[(String,Int)]= tuples.sortBy(one => one._2)
  9. tuples.sortBy(_._2)// 排序(元组)(第2个元素从大到小排序)
  10. println(tuples.sortBy((one => one._2))(Ordering[Int].reverse))// 5-3、自定义排序规则val tuples2: List[(String,Int)]= tuples.sortWith((left:(String,Int), right:(String,Int))=>{// 自定义规则
  11. left._2 > right._2
  12. })
  13. tuples.sortWith((a, b)=> a._2 > b._2)
  14. tuples.sortWith(_._2 > _._2)
7.4 高级函数
  • 过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合。
  • 转化/映射(map):将集合中的每一个元素映射到某一个函数。
  • 扁平化
  • 扁平化+映射:注:flatMap相当于先进行map操作,在进行flatten操作。集合中的每个元素的子元素映射到某个函数并返回新集合。
  • 分组(groupBy):按照指定的规则对集合的元素进行分组。
  • 简化(归约)
  • 折叠
  1. val list: List[Int]= List(1,2,3,4,5)val nestedList: List[List[Int]]= List(List(1,2,3), List(4,5,6))val wordList: List[String]= List("hello world","hello scala")// 1、过滤(List(2, 4))
  2. println(list.filter(x => x %2==0))// 2、转化、映射(List(2, 3, 4, 5, 6))
  3. println(list.map(x => x +1))// 3、扁平化(List(1, 2, 3, 4, 5, 6))
  4. println(nestedList.flatten)// 4、扁平化+映射(List(hello, world, hello, scala))
  5. println(wordList.flatMap(x => x.split(" ")))// 5、分组(Map(1 -> List(1, 3, 5), 0 -> List(2, 4)))
  6. println(list.groupBy(x => x %2))
  • Reduce简化(归约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果。
  1. val list: List[Int]= List(1,2,3,4)// 将数据两两结合,实现运算规则(1-2-3-4 = -8)
  2. println(list.reduce((x, y)=> x - y))// 从源码的角度,reduce底层调用的其实就是reduceLeft(1-2-3-4 = -8)
  3. println(list.reduceLeft((x, y)=> x - y))// (((4-3)-2-1) = -2)
  4. println(list.reduceRight((x, y)=> x - y))
  • Fold折叠:化简的一种特殊情况,可以添加初始值
  1. val list: List[Int]= List(1,2,3,4)// fold方法使用了函数柯里化,存在两个参数列表// 第一个参数列表为 : 零值(初始值)// 第二个参数列表为: 简化规则// fold底层其实为foldLeft
  2. println(list.foldLeft(1)((x, y)=> x - y))
  3. println(list.foldRight(10)((x, y)=> x - y))

8、队列

Scala也提供了队列

  1. Queue

的数据结构,队列的特点就是先进先出。进队和出队的方法分别为

  1. enqueue

  1. dequeue

  1. // 初始化对接val que: mutable.Queue[String]=new mutable.Queue[String]()// 插入元素(Queue(a, b, c))
  2. que.enqueue("a","b","c")// 弹出元素(a)
  3. println(que.dequeue())

七、模式匹配

1、基本语法

Scala中的模式匹配类似于Java中的switch语法

模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。

  • 如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句,若此时没有case _ 分支,那么会抛出MatchError。
  • 每个case中,不需要使用break语句,自动中断case。
  • match case语句可以匹配任何类型,而不只是字面量。
  • => 后面的代码块,直到下一个case语句之前的代码是作为一个整体执行,可以使用{}括起来,也可以不括。
  1. val num:Int=3val result:String= num match{case1=>"1"case2=>"2"case3=>"3"case _ =>"未匹配上"}// 3
  2. println(result)

2、常见匹配用法

匹配类型

需要进行类型判断时,可以使用前文所学的

  1. isInstanceOf[T]

  1. asInstanceOf[T]

,也可使用模式匹配实现同样的功能。

  1. def func(x:Any):String={
  2. x match{case a:Int=>"整数"case b:Char=>"字符"case c:String=>"字符串"case _ =>"其它"}}
  3. println(func(1))
  4. println(func('\t'))
  5. println(func("1232"))

执行结果:

  1. 整数
  2. 字符
  3. 字符串

匹配元组

  1. for(tuple <- Array((0,1),(1,0),(1,1),(1,0,2),(1,2,3,4))){val result:String= tuple match{// 匹配0开头case(0, _)=>"0 ..."// 匹配2个值case(y, _)=>""+ y +"0"// 匹配3个值case(a, b, c)=>""+ a +" "+ b +" "+ c
  2. case _ =>"other"}
  3. println(result)}

执行结果

  1. 0...1010102
  2. other

匹配对象

案例:

  1. object Test05 {def main(args: Array[String]):Unit={val person: Person5 =new Person5("张三",18)
  2. person match{case Person5("张三",18)=> println("找到张三了")case _ => println("你不是张三")}}}
  1. class Person05 (val name:String,var age:Int){}object Person05{// 创建对象的方法def apply(name:String, age:Int): Person05 =new Person05(name, age)// 解析对象的方法def unapply(arg: Person05): Option[(String,Int)]={// 如果解析的参数为nullif(arg ==null) None else Some((arg.name,arg.age))}}
  • val user = Person05("zhangsan",11),该语句在执行时,实际调用的是Person05伴生对象中的apply方法,因此不用new关键字就能构造出相应的对象。
  • 若只提取对象的一个属性,则提取器为unapply(obj:Obj):Option[T]若提取对象的多个属性,则提取器为unapply(obj:Obj):Option[(T1,T2,T3…)]若提取对象的可变个属性,则提取器为unapplySeq(obj:Obj):Option[Seq[T]]

匹配样例类

  1. caseclass Person05 (name:String, age:Int)
  1. caseclass Person05(var name:String, age:Int)
  • 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如applyunapplytoStringequalshashCodecopy
  • 样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法。
  • 构造器中的每一个参数都成为val,除非它被显式地声明为var(不建议这样做)

3、偏函数中的模式匹配

偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为List[Int],而我们需要的是第一个元素是0的集合,这就是通过模式匹配实现的

在这里插入图片描述

  1. // 返回输入的List集合的第二个元素。val second: PartialFunction[List[Int], Option[Int]]={case x :: y :: _ => Some(y)}

上述代码会被scala编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为Boolean。

  1. val second =new PartialFunction[List[Int], Option[Int]]{//检查输入参数是否合格overridedef isDefinedAt(list: List[Int]):Boolean= list match{case x :: y :: _ =>truecase _ =>false}//执行函数逻辑overridedef apply(list: List[Int]): Option[Int]= list match{case x :: y :: _ => Some(y)}}

偏函数调用

偏函数不能像second(List(1,2,3))这样直接使用,因为这样会直接调用apply方法,而应该调用applyOrElse方法

  1. second.applyOrElse(List(1,2,3),(_: List[Int])=> None)
  1. val list: List[Any]= List(1,2,3,4,5,6,7,8,9,"test")// 1、filter中使用val list1: List[Any]= list.filter(a =>{
  2. a match{case s:String=>falsecase i:Int=>true}})// 2、map中使用val list2: List[Int]= list1.map {case i:Int=> i +1}// 3、collect中使用val list3: List[Int]= list.collect({case i:Int=> i +1})// 4、PartialFunction 偏函数中使用val value: PartialFunction[Any,Int]={case i:Int=> i +1}// 5、偏函数中使用val function111:Any=>Int=(a:Any)=> a match{case i:Int=> i +1}// 6、isInstanceOf中使用
  3. List(1,2,3,4,5,6,"test").filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int]+1).foreach(println)// 7、collect中使用
  4. List(1,2,3,4,5,6,"test").collect {case x:Int=> x +1}.foreach(println)

4、下划线使用总结

  • 1、用于类中的var属性,使用默认值。
  • 2、用于高阶函数的第一种用法,表示函数自身。
  • 3、匿名函数化简,用下划线代替变量。
  • 4、用于导包下的所有内容。
  • 5、用于起别名时表示匿名。
  • 6、用于模式匹配表示任意数据。
  1. class Person001 {// 1、用于类中的var属性,使用默认值。var name1:String= _
  2. }
  1. // 2、用于高阶函数的第一种用法,表示函数自身。def sayHi(name:String):Unit={
  2. println(s"hi $name")}val function:String=>Unit= sayHi _
  3. // 3、匿名函数化简,用下划线代替变量。val function01:(Int,Int)=>Int=(a:Int, b:Int)=> a + b
  4. val function02:(Int,Int)=>Int= _ + _
  5. // 4、用于导包下的所有内容。importscala.util.control.Breaks._
  6. // 5、用于起别名时表示匿名。importscala.util.control.{Breaks => _}// a / Breaks// 6、用于模式匹配表示任意数据。10match{case10=>"10"case _ =>"other"}

八、异常

  • Scala没有“checked(编译期)”异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理。
  • 如果有异常发生,catch子句是按次序捕捉的。
  • finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作。
  • 用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方
  1. def test():Nothing={thrownew Exception("不对")}
  • Java提供了throws关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止。在Scala中,可以使用throws注解来声明异常。
  1. def main(args: Array[String]):Unit={
  2. f11()}@throws(classOf[NumberFormatException])def f11()={"abc".toInt
  3. }

完整代码:

  1. def main(args: Array[String]):Unit={try{val n =10/0}catch{case ex: ArithmeticException =>{
  2. println("发生算数异常")}// 抛出异常case ex: NullPointerException =>{throw NullPointerException
  3. }case ex: Exception =>{
  4. println("发生了其他异常")}}finally{
  5. println("finally")}}

执行结果

  1. 发生算数异常
  2. finally

九、隐式转换

当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译,用于拓展类的方法。

隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。

  1. object Test02_Imp {def main(args: Array[String]):Unit={// 隐式函数// 将当前作用域下所有传入参数的类型 隐式转换为 返回值类型implicitdef changeInt(self:Int)={new MyRichInt(self)}val i:Int=10// 比较自身和传入参数的大小 返回较大的值val value:Int= i.myMax(20)
  2. println(value)val i1:Int= i <<2
  3. println(i1)}// 隐式转换的目标class MyRichInt(valself:Int){def myMax(i:Int):Int={if(i >self) i elseself}// 如果隐式转换和自身的方法冲突 会使用它自身的 因为不会编译失败def<<(x:Int):Int={0}}}

本文转载自: https://blog.csdn.net/weixin_44624117/article/details/133219900
版权归原作者 ha_lydms 所有, 如有侵权,请联系我们删除。

“Scala最基础入门教程”的评论:

还没有评论