赞
踩
–
官方编程指南https://www.scala-lang.org/
Scala将面向对象和函数式编程结合成一种简洁的高级语言。
语言特点如下:
(1)Scala和Java一样属于JVM语言,使用时都需要先编译为class字节码文件,并且Scala能够直接调用Java的类库。
(2)Scala支持两种编程范式面向对象和函数式编程。
(3)Scala语言更加简洁高效;语法能够化简,函数式编程的思想使代码结构简洁。
(4)作者马丁·奥德斯基设计Scala借鉴了Java的设计思想,同时优秀的设计也推动了Java语言的发展。
新建项目
添加scala插件
添加项目支持
添加Scala安装包
新建Scala文件夹,并指定为源文件
新建代码文件
object HelloWorld {
def main(args: Array[String]): Unit = {
// java的方法调用
System.out.println("hello scala")
// scala的方法调用
println("hello scala")
}
}
基本语法
基本语法
(1)单行注释://
(2)多行注释:/* */
(3)文档注释:/**
*
*/
**常量:**在程序执行的过程中,其值不会被改变的变量。
1)基本语法
var 变量名 [: 变量类型] = 初始值 var i:Int = 10
val 常量名 [: 常量类型] = 初始值 val j:Int = 20
注意:能用常量的地方不用变量。
特征:
....
包括的任意字符串,即使是Scala关键字(39个)也可以1、字符串,通过+号拼接
// 1、字符串,通过+号拼接
System.out.println()
println("hello" + "world")
2、重复字符串拼接
// 2、重复字符串拼接
println("lilei " * 20)
3、printf用法:字符串,通过%传值
// 3、printf用法:字符串,通过%传值
printf("name:%s age %d\n", "linlai", 8)
4、字符串模板(插值字符串):通过$获取变量值
s""
:标明当前是需要取值计算的字符串
$name
:取变量name
值,赋值到字符串中。
${age+1}
:取变量age
值,并进行计算+1.
// 4、字符串模板(插值字符串):通过$获取变量值
val name = "linhai"
val age = 8
val s1 = s"name:$name,age:${age}"
println(s1)
val s2 = s"name:${name + 1},age:${age + 2}"
println(s2)
5、多行字符串
// 5、多行字符串 println("我" + "是" + "中国人") println( """我 |是 |中国 |人 |""".stripMargin) val margin = """ |我 |是 |中国人 |""".stripMargin
数据类型 | 描述 |
---|---|
Byte [1] | 8位有符号补码整数。数值区间为 -128 到 127 |
Short [2] | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int [4] | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long [8] | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 = 2的(64-1)次方-1 |
val a1: Byte = 1
val a2: Short = 2
val a3: Int = 3
val a4: Long = 4
数据类型 | 描述 |
---|---|
Float [4] | 32 位, IEEE 754标准的单精度浮点数 |
Double [8] | 64 位 IEEE 754标准的双精度浮点数 |
val b1: Double = 3.14
// 默认为Double类型
val b2 = 3.14
val b3: Float = 3.14f
字符类型可以表示单个字符,字符类型是Char。
val c1: Char = 'a'
val c2: Char = 523
val c3: Char = '\t'
val c4: Char = '\n'
val c5: Char = '\\'
val c6 = '\"'
val bo1: Boolean = true
val bo2: Boolean = false
数据类型 | 描述 |
---|---|
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null , Null 类型只有一个实例值null |
Nothing | Nothing类型在Scala的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
val u1: Unit = {
10
println(10)
}
println(u1)
// 如果标记对象的类型是unit的话 后面有返回值也没法接收
// unit虽然是数值类型 但是可以接收引用数据类型 因为都是表示不接收返回值
val u2: Unit = 10
println(u2)
打印结果:
10
()
()
var n2: String = "bb"
n2 = "cc"
n2 = null
// 值类型不能等于null,idea不会识别报错 编译器会报错
var i4 = 10
// i4 = null
// 可以用来抛出异常
// 可以接收任意数据类型(Int使用Nothing接收)
val value: Nothing = {
println("hello")
1 + 1
throw new RuntimeException()
}
当Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:
// 自动类型提升,以最大的类型进行结果存储
val f1: Float = 1 + 1L + 3.14f
val f2: Double = 1 + 1L + 3.14
val f3: Double = 1 + 1L + 3.14f + 3.14
// 把精度大的赋值给精度小的会报错,反之会进行类型转换
val i = 10
val b: Double = i
// (byte、short、char)之间不会相互转换
val b1: Byte = 10
val c1: Char = 20
// byte,short,char他们三者可以计算,在计算时首先转换为int类型。
val b2: Byte = 20
val i1: Int = b1 + b2
自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
Java : int num = (int)2.5
Scala : var num : Int = 2.7.toInt
// 1、将高精度转为低精度,就需要使用强制转换
val int = 2.99.toInt
val int1 = (10 * 3.5 + 6 * 1.5).toInt
基本类型转String类型(语法:将基本类型的值+“” 即可)。
String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)。
// 1、基本类型转为String类型
val str = 1 + ""
// 2、string类型转为数值类型
val d1 = "3.14".toDouble
val d2 = "1".toInt
// 3、小数类型,需先转为Double再转为Int类型
val i1 = "3.14".toDouble.toInt
// 标记为f的float数能够识别
val i02 = "12.5f".toFloat
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | b=4; -b | -4 |
+ | 加 | 5+5 | 10 |
- | 减 | 6-4 | 2 |
* | 乘 | 3*4 | 12 |
/ | 除 | 5/5 | 1 |
% | 取模(取余) | 7%5 | 2 |
+ | 字符串相加 | “He”+”llo” | “Hello” |
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
== | 相等于 | 4==3 | false |
!= | 不等于 | 4!=3 | true |
< | 小于 | 4<3 | false |
> | 大于 | 4>3 | true |
<= | 小于等于 | 4<=3 | false |
>= | 大于等于 | 4>=3 | true |
// ==比较两个变量本身的值,即两个对象在内存中的首地址;
// equals比较字符串中所包含的内容是否相同。
println("a".equals("b"))
println("a" == "b")
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑与 | (A && B) 运算结果为 false |
|| | 逻辑或 | (A || B) 运算结果为 true |
! | 逻辑非 | !(A && B) 运算结果为 true |
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | 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 |
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符 | (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 |
var a:Int=1000
// 4000
println(a << 2)
// 250
println(a >> 2)
在Scala中其实是没有运算符的,所有运算符都是方法。
var nu1: Int = 1.+(1)
val nu2: Int = 1 + (1)
val nu3: Int = 1 + 1
让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支。
// 1、简单If-else if (age < 18) { println("童年") } else if (age > 18 && age < 60) { println("中年") } else { println("老年") } // 2、使用方法计算 val result: String = { if (age < 18) { "童年" } else { "老年" } } println(result) // 3、不确定返回值类型。使用Any代替 val res: Any = { if (age > 18) { "童年" } else { 100 } } println(res) // 4、三元运算符使用 val res01: Any = if (age > 18) "童年" else "中年" println(res01)
for (i <- 0 to 5) { println(i) } for (i <- 0 until 5) { println(i) } for (i <- 0 to 5) { if (i > 1) { print(i) } } for (i <- 0 to 5 if i > 2) { print(i) } // (10, 10, 10, 10) val ints: immutable.IndexedSeq[Int] = for (i <- 0 to 3) yield { 10 }
var i = 0
// while循环
while (i < 5) {
println(i)
i += i
}
// do-while循环
do {
println(i)
i += i
} while (i < 5)
Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数式编程,推荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable控制结构来实现break和continue功能。
// 1、采用异常的方式退出循环 try { for (e <- 1 to 5) { println(e) if (e > 4) { throw new Exception() } } } catch { case e: Throwable => } // 2、采用Scala自带的函数,退出循环 Breaks.breakable( for (e <- 1 to 5) { println(e) if (e > 4) { Breaks.break() } } ) // 3、对break进行省略 breakable { for (e <- 1 to 10) { if (e > 9) { break } } }
object Hello {
def main(args: Array[String]): Unit = {
// 自定义方法:f:方法名。arg:参数名。String:参数类型。Unit:返回值空
def f(arg: String): Unit = {
println(arg)
}
// 调用方法
f("hello world")
}
}
// 有参。有返回值 def f1(arg: String): String = { arg + " world" } println(f1("hello")) // 有参。无返回值 def f2(args: String): Unit = { println(args) } println(f2("hello")) // 无参。有返回值 def f3(): String = { "hello world" } println(f3()) // 无参。无返回值 def f4(): Unit = { println("hello world") } f4() // 多参。无返回值 def f5(args01: String, args02: String): Unit = { args01 + args02 } f5("hello", "world")
方法至简原则
// 1、return可以省略,Scala会使用方法体的最后一行代码作为返回值 def s1(): String = { "hello01" "hello02" } // 2、如果方法体只有一行代码,可以省略花括号 def s2(): Int = 1 + 2 // 3、返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)特别注意事项: def s3() = 1 + 2 // 4、如果有return,则不能省略返回值类型,必须指定 def s4(): Int = { return 1 + 2 } // 5、如果方法明确声明unit,那么即使方法体中使用return关键字也不起作用 def s5(): Unit = { return 1 + 2 } // 6、Scala如果期望是无返回值类型,可以省略等号(=号和方法体大括号不能同时省略) def s6() { println(1 + 1) } // 7、如果方法无参,但是声明了参数列表,那么调用时,小括号,可加可不加(声明无括号调用时也没有括号) def s7(): Unit = { println(1 + 2) } s7() s7 // 8、如果方法没有参数列表,那么小括号可以省略,调用时小括号必须省略 def s8 { println("hello") } s8
// 1、可变参数。本质是1个数组 def sayHi(name: String*): Unit = { println(s"hi $name") for (e <- name) { println(name) } } sayHi("hello01", "hello02", "hell03") // 2、可变参数必须要放在参数列表最后 def sayHi2(age: Int, name: String*): Unit = { println(s"hi $name") } sayHi2(18, "hello01", "hello02") // 3、参数默认值 def sayHi3(age: Int, name: String = "张三"): Unit = { println(s"hi $age $name") } // hi 18 张三 sayHi3(18) // 4、默认值参数在使用的时候,可以不在最后 def say4(name: String = "张三", age: Int): Unit = { println(s"hi $age $name") } sayHi3(18)
函数的返回值就是函数体中最后一个表达式的结果值/return语句的返回值。
函数和方法的区别
// 不支持重载 val test = () => { println("无参") } test() // val test =(name:String)=>{ // println("构造") // } // 3、函数可以嵌套 val test02 = () => { val test03 = () => { println("无参+构造") } println("无参") } test02() // 4、方法可以转为函数 def add(): Unit = { println("方法") } val add2 = add _
参数/返回值为函数的方法/函数称为高阶函数
// 函数ope作为参数传入,
def cal(a: Int, b: Int, ope: (Int, Int) => Int): Int = {
ope(a, b)
}
// 函数求和
def plus(x: Int, y: Int): Int = {
x + y
}
println(cal(1, 3, plus))
没有名字的函数/方法就是匿名函数。
(x:Int)=>{函数体}
x:表示输入参数名称;Int:表示输入参数类型;函数体:表示具体代码逻辑
参数的类型可以省略,会根据形参进行自动的推导
类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略圆括号。
匿名函数如果只有一行,则大括号也可以省略
如果参数只出现一次,且按照顺序出现则参数省略且后面参数可以用_代替
val f0: (Int, Int) => Int = (x: Int, y: Int) => x + y
// 1、参数的类型可以省略,会根据形参自动推导
val f1: (Int, Int) => Int = (x, y) => x + y
//2、类型省略后,发现只有1个参数,则圆括号可以省略
val f2: (Int, Int) => Int = (x, y) => x + y
val f3: Int => Int = x => x + 22
val f4: () => Int = () => 22
// 3、匿名函数如果只有一行,则大括号也可以省略
val f5: (Int, Int) => Int = (x, y) => {
x + y
}
val f6: (Int, Int) => Int = (x, y) => x + y
// 4、如果参数只出现一次,且按照顺序出现,则参数省略且后面的参数可以用_代替
val f7: (Int, Int) => Int = _ + _
不能化简为下划线的情况: 1.化简之后只有一个下划线 2.化简后的函数存在嵌套
// 1、传入的参数类型可以推断 所以可以省略
val f8: (Int, Int) => Int = (x, y) => y - x
val f8_1: (Int, Int) => Int = _ - _
// 2、参数必须只使用一次,使用的顺序必要和定义的顺序一直
val f9: (Int, Int) => Int = -_ + _
**函数柯里化:**将一个接收多个参数的函数转化成一个接受一个参数的函数过程,可以简单的理解为一种特殊的参数列表声明方式。
**闭包:**就是一个函数和与其相关的引用环境(变量)组合的一个整体(实体)
// 外部参数
var z: Int = 10
// 闭包
def f(y: Int): Int = {
z + y
}
1
// 原样 val sum = (x: Int, y: Int, z: Int) => x + y + z sum(1, 2, 3) // 1、 val sum1 = (x: Int) => { y: Int => { z: Int => { x + y + z } } } sum1(1)(2)(3) // 2、第二种 val sum2 = (x: Int) => (y: Int) => (z: Int) => x + y + z sum2(1)(2)(3) // 3、第三种 def sum3(x: Int)(y: Int)(z: Int) = x + y + z sum3(1)(2)(3)
一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用
def main(args: Array[String]): Unit = {
println(test(5))
}
// 递归方法(test方法)
def test(i: Int): Int = {
if (i == 1) {
1
} else {
i * test(i - 1)
}
}
基本语法
[修饰符] class 类名 {
类体
}
package com.atguigu.chapter06
//(1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)
class Person {
}
//(2)一个Scala源文件可以包含多个类
class Teacher{
}
class Person {
@BeanProperty
var age: Int = _
// val只能生成get方法
@BeanProperty
val name: String = "张三"
}
测试类
object Test {
def main(args: Array[String]): Unit = {
val person = new Person
person.age = 18
person.setAge(18)
println(person.getName)
}
}
def 方法名(参数列表) [:返回值类型] = {
方法体
}
案例
class Person {
def sum(n1: Int, n2: Int): Int = {
n1 + n2
}
}
object Test01 {
def main(args: Array[String]): Unit = {
val test: Test01 = new Test01()
println(test.sum(1, 2))
}
}
和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。
Scala类的构造器包括:主构造器和辅助构造器
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
案例:
// 主构造器 class Person01(name: String) { val name1: String = name var age: Int = _ // 辅助构造器01 def this() = { this("张三") } // 复制构造器02 def this(name: String, age1: Int) = { this() this.age = age1 } }
测试类
object Test {
def main(args: Array[String]): Unit = {
val person01: Person01 = new Person01()
val person02: Person01 = new Person01("张三")
val person03: Person01 = new Person01("张三", 18)
}
}
Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰
// 主构造器参数 分为3类:
// 没有修饰符: 作为构造方法中的传入参数使用
// val 修饰: 会自动生产同名的属性 并且定义为val
// var 修饰 : 会自动生产同名的属性 并且定义为var
class Person02(name1: String, var age1: Int, val sex1: Int) {
val name: String = name1
}
// 等效方法
class Person02(name1: String, age1: Int,sex1 : Int) {
val name: String = name1
val age: Int = age1
val sex: Int = sex1
}
java中存在静态属性、静态方法、非静态属性、非静态方法。
object TestObject {
val name: String = "zhansan"
var age: Int = 30
private val address: String = "深圳"
def getName(): String = {
this.name + " " + this.name
}
val func = (x: Int, y: Int) => {
x * y
}
}
object Test102 { def main(args: Array[String]): Unit = { // object中的属性直接通过 类名.属性名 方式调用(zhansan) println(TestObject.name) // 30 println(TestObject.age) // 设置属性 TestObject.age = 66 // 66 println(TestObject.age) println("====") // object中的方法直接通过 类名.方法名 方式调用(zhansan zhansan) println(TestObject.getName()) // object中的方法直接通过 类名.函数名 方式调用(6) println(TestObject.func(2, 3)) } }
如果满足上两个条件,那么就称这个object为class的伴生对象,称class为object的伴生类。
class ClassObjectTest { val name:String = "lisi" //用private修饰的只能在类或者伴生对象中使用 private val age = 20 //此时可以调用伴生对象中用private修饰的 address属性 def getAddress() = ClassObjectTest.address } object ClassObjectTest{ private val address = "shenzhen" def getName() = { //创建伴生类的对象 val obj = new ClassObjectTest() //此时可以调用伴生类中用private修饰的name属性 obj.name } }
obj(arg)
的语句实际是在调用该对象的apply
方法,即obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。object Test11_Apply { def main(args: Array[String]): Unit = { // 如果调用的方法是apply的话 方法名apply可以不写 val one: Person11 = Person11() // 类的apply方法调用(打印类方法) one() } } class Person11 private() { var name:String = _ def this(name:String){ this() this.name = name } def apply(): Unit = println("类的apply方法调用") } object Person11 { // 使用伴生对象的方法来获取对象实例 def getPerson11: Person11 = new Person11 // 伴生对象的apply方法 def apply(): Person11 = new Person11() // apply方法的重载 def apply(name: String): Person11 = new Person11(name) } }
// 判断obj是不是T类型。
obj.isInstanceOf[T]
// 将obj强转成T类型。
obj.asInstanceOf[T]
// 获取类模板。
classOf
// 判断person类型是不是为Teacher
if (person1.isInstanceOf[Teacher]) {
// 假如类型为Teacher,则强转为Teacher
val teacher1: Teacher = person1.asInstanceOf[Teacher]
teacher1.sayHi1()
}
// 调用固定的方法 返回类模板
val value: Class[Student15] = classOf[Student15]
Scala的集合有三大类:序列Seq(List)、集Set、映射Map,所有的集合都扩展自Iterable特质。
对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本,分别位于以下两个包。
Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于java中的String对象。
可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于java中StringBuilder对象。
建议:在操作集合的时候,不可变用符号,可变用方法。
不可变集合
可变集合
val arr1 = new Array[Int](10)
new
是关键字。[Int]
是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any。(10)
,表示数组的大小,确定后就不可以变化。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打印) println(array01.toList) // 遍历数组(遍历) for (e <- array01) { println(e) } // 遍历数组(迭代器) val iterator: Iterator[Int] = array01.iterator while (iterator.hasNext) { println(iterator.next()) } // 遍历数组(匿名函数) array01.foreach(e => println(e)) // 遍历数组(使用系统函数) array01.foreach(println) // 修改数组值 array01(0) = 10 println(array01(0)) // 添加元素,生成新数组array02、原数组array01不变 val array02: Array[Int] = array01 :+ 1 } }
定义:
[Any]
存放任意数据类型。scala.collection.mutable.ArrayBuffer
。 val array: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
ArrayBuffer是有序的集合。
增加元素使用的是append方法(),支持可变参数。
// 创建可变数组 val array: ArrayBuffer[Int] = new ArrayBuffer[Int]() val arrayBuffer02: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4) // 向可变数组中添加元素 array.append(10) array.appendAll(Array(1, 2, 3, 4)) // 循环打印 array.foreach(println) println(array) // 更新元素值 array.update(0, 100) array(1) = 200 println(array) println(array(0)) // 删除元素 array.remove(0) array.remove(1, 3)
arr2.toArray
返回结果才是一个不可变数组,arr2本身没有变化。arr1.toBuffer
返回结果才是一个可变数组,arr1本身没有变化。// 不可变数组转可变数组
arr1.toBuffer
// 不可变数组转可变数组
arr2.toArray
// 不可变数组
val array: Array[Int] = Array(1, 2, 3, 4)
// 可变数组
val arrayBuffer: ArrayBuffer[Int] = ArrayBuffer(5, 6, 7, 8)
// 添加元素(不可变数组)
val arra01: Array[Int] = array :+ 1
arrayBuffer.append(1)
// 可变 => 不可变
val array01: Array[Int] = arrayBuffer.toArray
// 不可变 => 可变
val buffer: mutable.Buffer[Int] = array.toBuffer
val arrayBuffer01: ArrayBuffer[Int] = buffer.asInstanceOf[ArrayBuffer[Int]]
// 3行4列
val array02: Array[Array[Double]] = Array.ofDim[Double](3, 4)
val arrayDim: Array[Array[Double]] = Array.ofDim[Double](3, 4)
// 赋值
arrayDim(0) = Array(1, 2, 3, 4)
arrayDim(0)(1) = 100
// 遍历
for (array <- arrayDim) {
for (elem <- array) {
print(elem + " ")
}
}
不可变List
// 创建集合(List) val list01: List[Any] = List(1, 1, 1, 1.0, "hello", 'c') val list02: List[Int] = List(1, 2, 3, 4) // 遍历集合 list01.foreach(println) // 增加数据(末尾增加) val list011: List[Any] = list01 :+ 1 // 增加数据(开头增加) val list012: List[Any] = 2 :: list011 // 合并2个集合(1个集合插入另1个集合中)(List(List(1, 1, 1, 1.0, hello, c), 1, 2, 3, 4)) val list013: List[Any] = list01 :: list02 // 合并2个集合(1个集合元素遍历插入另1集合)(List(1, 1, 1, 1.0, hello, c, 1, 2, 3, 4)) println(list01 ::: list02) // 取值 val value: Int = list02(2) // 空集合Nil(List(1, 2, 3, 4)) val ints: List[Int] = 1 :: 2 :: 3 :: 4 :: Nil
可变ListBuffer
// 可变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))
listBuffer.append(5)
// 添加元素(开头)(ListBuffer(0, 5))
listBuffer.prepend(0)
// 删除元素(ListBuffer(5))
listBuffer.remove(0)
// 更新值(ListBuffer(5))
listBuffer(0)=1
默认情况下,Scala使用的是不可变集合,如果你想使用可变集合,需要引用 scala.collection.mutable.Set
包。
不可变集合
hash set
。val set: Set[Int] = Set(3, 2, 4, 1)
// set的特点 无序不可重复
println(set)
// 不可变使用符号(无变化s)(Set(3, 2, 4, 1))
val set2: Set[Int] = set + 1
println(set)
println(set2)
// 作用 判断集合是否包含某个元素(true)
val bool: Boolean = set.contains(2)
println(bool)
可变集合mutable.Set
// 创建可变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)
// 遍历
set.foreach(println)
// 删除元素(Set(1, 5, 3, 4))
val bool1: Boolean = set.remove(2)
println(set)
Scala中的Map和Java类似,**也是一个散列表,它存储的内容也是键值对(key-value)**映射。
不可变Map
// 1、创建不可变Map val map: Map[String, Int] = Map("hello" -> 100, "world" -> 200) val map02: Map[String, Int] = Map(("hello", 100), ("world", 200)) // 2、遍历打印 for (elem <- map) { println(elem) } // 遍历打印(foreach打印) map.foreach(print) // 遍历打印(打印key) val keys: Iterable[String] = map.keys keys.foreach(print) // 遍历打印(打印value) val values: Iterable[Int] = map.values // 遍历打印(直接打印) println(map) // 3-1、获取value的值(Option) val option: Option[Int] = map.get("hello") // 根据Option取值(option.isDefined/option.isEmpty) if (!option.isEmpty) { println(option.get) } 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
// 创建可变map
val map: mutable.Map[String, Int] = mutable.Map(("a", 1), ("b", 1), ("c", 2), ("d", 4))
println(map)
// 添加元素
map.put("z", 10)
println(map)
// 修改元素值
map.update("b", 20)
map("a") = 30
// 删除元素
map.remove("a")
// 1、声明元组
val tuple: (Int, String, Boolean) = (40, "bobo", true)
// 2-1、访问元组(单个)
println(tuple._1)
// 2-2、访问元组(单个)
val value: Any = tuple.productElement(0)
println(value)
// 2-3、访问元组(迭代器遍历)
for (elem <- tuple.productIterator) {
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))
val list: List[Int] = List(1, 2, 3, 4, 5, 6)
// 获取集合长度
println(list.length)
// 获取集合的大小(size=length)
println(list.size)
// 循环遍历
list.foreach(println)
// 迭代器
for (elem <- list.iterator) {
println(elem)
}
// 按规定字符串(1,2,3,4,5,6)
println(list.mkString(","))
// 是否包含(true)
println(list.contains(3))
val list: List[Int] = List(1, 2, 3) val list02: List[Int] = List(3,4, 5) // 获取集合的头(1) println(list.head) // 获取集合最后1个元素(3) println(list.last) // 集合头数据(不包含最后1个)(List(1, 2)) println(list.init) // 获取集合的尾(不包含第1个)(List(2, 3)) println(list.tail) // 反转(List(3, 2, 1)) println(list.reverse) // 取前(后)n个元素 println(list.take(2)) println(list.takeRight(2)) // 去掉前(后)n个元素(List(3))(List(1)) println(list.drop(2)) println(list.dropRight(2)) // 并集(List(1, 2, 3, 4, 5)) println(list.union(list02)) // 交集(List(3)) println(list.intersect(list02)) // 差集(List(1, 2)) println(list.diff(list02)) // 拉链(List((1,3), (2,4), (3,5))) println(list.zip(list02)) // 划窗(List(1, 2)) list.sliding(2, 5).foreach(println)
sorted
:对一个集合进行自然排序,通过传递隐式的Ordering。sortBy
:对一个属性或多个属性进行排序,通过它的类型。sortWith
:基于函数的排序,通过一个comparator函数,实现自定义排序的逻辑。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、求和 println(list.sum) // 2、求乘积 println(list.product) // 3、最大值 println(list.max) // 4、最小值 println(list.min) // 5-1、排序(默认)(从小到大) println(list.sorted) // 排序(从大到小) println(list.sorted(Ordering[Int].reverse)) // 5-2、排序(元组) val tuples: List[(String, Int)] = List(("hello", 10), ("world", 12), ("scala", 9)) // 排序(元组)(默认字典序) println(tuples.sorted) // 排序(元组)(第2个元素从小到大排序) val tuples1: List[(String, Int)] = tuples.sortBy(one => one._2) tuples.sortBy(_._2) // 排序(元组)(第2个元素从大到小排序) println(tuples.sortBy((one => one._2))(Ordering[Int].reverse)) // 5-3、自定义排序规则 val tuples2: List[(String, Int)] = tuples.sortWith((left: (String, Int), right: (String, Int)) => { // 自定义规则 left._2 > right._2 }) tuples.sortWith((a, b) => a._2 > b._2) tuples.sortWith(_._2 > _._2)
**过滤:**遍历一个集合并从中获取满足指定条件的元素组成一个新的集合。
**转化/映射(map):**将集合中的每一个元素映射到某一个函数。
扁平化
**扁平化+映射:**注:flatMap相当于先进行map操作,在进行flatten操作。集合中的每个元素的子元素映射到某个函数并返回新集合。
**分组(groupBy):**按照指定的规则对集合的元素进行分组。
简化(归约)
折叠
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))
println(list.filter(x => x % 2 == 0))
// 2、转化、映射(List(2, 3, 4, 5, 6))
println(list.map(x => x + 1))
// 3、扁平化(List(1, 2, 3, 4, 5, 6))
println(nestedList.flatten)
// 4、扁平化+映射(List(hello, world, hello, scala))
println(wordList.flatMap(x => x.split(" ")))
// 5、分组(Map(1 -> List(1, 3, 5), 0 -> List(2, 4)))
println(list.groupBy(x => x % 2))
val list: List[Int] = List(1, 2, 3, 4)
// 将数据两两结合,实现运算规则(1-2-3-4 = -8)
println(list.reduce((x, y) => x - y))
// 从源码的角度,reduce底层调用的其实就是reduceLeft(1-2-3-4 = -8)
println(list.reduceLeft((x, y) => x - y))
// (((4-3)-2-1) = -2)
println(list.reduceRight((x, y) => x - y))
val list: List[Int] = List(1, 2, 3, 4)
// fold方法使用了函数柯里化,存在两个参数列表
// 第一个参数列表为 : 零值(初始值)
// 第二个参数列表为: 简化规则
// fold底层其实为foldLeft
println(list.foldLeft(1)((x, y) => x - y))
println(list.foldRight(10)((x, y) => x - y))
Scala也提供了队列(Queue)
的数据结构,队列的特点就是先进先出。进队和出队的方法分别为enqueue
和dequeue
。
// 初始化对接
val que: mutable.Queue[String] = new mutable.Queue[String]()
// 插入元素(Queue(a, b, c))
que.enqueue("a","b","c")
// 弹出元素(a)
println(que.dequeue())
Scala中的模式匹配类似于Java中的switch语法
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。
=>
后面的代码块,直到下一个case语句之前的代码是作为一个整体执行,可以使用{}
括起来,也可以不括。val num: Int = 3
val result: String = num match {
case 1 => "1"
case 2 => "2"
case 3 => "3"
case _ => "未匹配上"
}
// 3
println(result)
匹配类型
需要进行类型判断时,可以使用前文所学的isInstanceOf[T]
和asInstanceOf[T]
,也可使用模式匹配实现同样的功能。
def func(x: Any): String = {
x match {
case a: Int => "整数"
case b: Char => "字符"
case c: String => "字符串"
case _ => "其它"
}
}
println(func(1))
println(func('\t'))
println(func("1232"))
执行结果:
整数
字符
字符串
匹配元组
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
case _ => "other"
}
println(result)
}
执行结果
0 ...
10
10
1 0 2
other
匹配对象
案例:
object Test05 {
def main(args: Array[String]): Unit = {
val person: Person5 = new Person5("张三", 18)
person match {
case Person5("张三", 18) => println("找到张三了")
case _ => println("你不是张三")
}
}
}
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)] = {
// 如果解析的参数为null
if (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]]
匹配样例类
case class Person05 (name: String, age: Int)
case class Person05(var name: String, age: Int)
apply
、unapply
、toString
、equals
、hashCode
和copy
。unapply
方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply
方法。val
,除非它被显式地声明为var
(不建议这样做)偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查。例如该偏函数的输入类型为List[Int],而我们需要的是第一个元素是0的集合,这就是通过模式匹配实现的
// 返回输入的List集合的第二个元素。
val second: PartialFunction[List[Int], Option[Int]] = {
case x :: y :: _ => Some(y)
}
上述代码会被scala编译器翻译成以下代码,与普通函数相比,只是多了一个用于参数检查的函数——isDefinedAt,其返回值类型为Boolean。
val second = new PartialFunction[List[Int], Option[Int]] {
//检查输入参数是否合格
override def isDefinedAt(list: List[Int]): Boolean = list match {
case x :: y :: _ => true
case _ => false
}
//执行函数逻辑
override def apply(list: List[Int]): Option[Int] = list match {
case x :: y :: _ => Some(y)
}
}
偏函数调用
偏函数不能像second(List(1,2,3))这样直接使用,因为这样会直接调用apply方法,而应该调用applyOrElse方法
second.applyOrElse(List(1,2,3), (_: List[Int]) => None)
val list: List[Any] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, "test") // 1、filter中使用 val list1: List[Any] = list.filter(a => { a match { case s: String => false case 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中使用 List(1, 2, 3, 4, 5, 6, "test").filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int] + 1).foreach(println) // 7、collect中使用 List(1, 2, 3, 4, 5, 6, "test").collect { case x: Int => x + 1 }.foreach(println)
class Person001 {
// 1、用于类中的var属性,使用默认值。
var name1: String = _
}
// 2、用于高阶函数的第一种用法,表示函数自身。 def sayHi(name: String): Unit = { println(s"hi $name") } val function: String => Unit = sayHi _ // 3、匿名函数化简,用下划线代替变量。 val function01: (Int, Int) => Int = (a: Int, b: Int) => a + b val function02: (Int, Int) => Int = _ + _ // 4、用于导包下的所有内容。 import scala.util.control.Breaks._ // 5、用于起别名时表示匿名。 import scala.util.control.{Breaks => _} // a / Breaks // 6、用于模式匹配表示任意数据。 10 match { case 10 => "10" case _ => "other" }
def test():Nothing = {
throw new Exception("不对")
}
def main(args: Array[String]): Unit = {
f11()
}
@throws(classOf[NumberFormatException])
def f11()={
"abc".toInt
}
完整代码:
def main(args: Array[String]): Unit = { try { val n = 10 / 0 } catch { case ex: ArithmeticException => { println("发生算数异常") } // 抛出异常 case ex: NullPointerException => { throw NullPointerException } case ex: Exception => { println("发生了其他异常") } } finally { println("finally") } }
执行结果
发生算数异常
finally
当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译,用于拓展类的方法。
隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。
object Test02_Imp { def main(args: Array[String]): Unit = { // 隐式函数 // 将当前作用域下所有传入参数的类型 隐式转换为 返回值类型 implicit def changeInt(self: Int) = { new MyRichInt(self) } val i: Int = 10 // 比较自身和传入参数的大小 返回较大的值 val value: Int = i.myMax(20) println(value) val i1: Int = i << 2 println(i1) } // 隐式转换的目标 class MyRichInt(val self: Int) { def myMax(i: Int): Int = { if (i > self) i else self } // 如果隐式转换和自身的方法冲突 会使用它自身的 因为不会编译失败 def <<(x: Int): Int = { 0 } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。