scala 是一门以 jvm 为运行环境的静态类型编程语言,具备面向对象 及 函数式编程的特性
六大特征 :
不推荐使用 var
,推荐使用 val
Scala 应用场景
Scala的数据类型都是
对象
,也就是说scala没有java中的原生类型。在scala是可以对数字等基础类 型调用方法的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMi3rgwa-1658889492338)(C:\Users\58266\AppData\Roaming\Typora\typora-user-images\1657870236960.png)]
/**
* 定义变量和常量
* 变量 :用 var 定义 ,可修改
* 常量 :用 val 定义,不可修改
*/
var name = "zhangsan"
println(name)
name ="lisi"
println(name)
val gender = "m"
//gender = "w" //错误,不能给常量再赋值
一个运算符是一个符号,用于告诉编译器来执行指定的数学运算和逻辑运算。
- scala减去了++ 与 –
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vOj7a4W-1658889492339)(C:\Users\58266\AppData\Roaming\Typora\typora-user-images\1657870937311.png)]
循环语句允许我们多次执行一个语句或语句组
区间获取
/**
* to和until
* 例:
* 1 to 10 返回1到10的Range数组,包含10
* 1 until 10 返回1到10 Range数组 ,不包含10
*/
(1 to 10).foreach(print)//打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
(1 to 10).foreach(print)//与上面等价,打印 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
println(1 to (10 ,2))//步长为2,从1开始打印 ,1,3,5,7,9
println(1.to(10, 2))
println(1 until 10 ) //不包含最后一个数,打印 1,2,3,4,5,6,7,8,9
println(1.until(10))//与上面等价
println(1 until (10 ,3 ))//步长为2,从1开始打印,打印1,4,7
//借助数组的区间 类似于 until
Array.range(10, 20)
Array.range(10, 20, 2)
普通for循环
/**
* Range 可以是一个数字区间表示 i to j ,或者 i until j。左箭头 <- 用于为变量 x
赋值。
*/
for( var x <- Range ){
statement(s);
}
多层for循环
//可以分号隔开,写入多个list赋值的变量,构成多层for循环
//scala中 不能写count++ count-- 只能写count+
var count = 0;
for(i <- 1 to 10; j <- 1 until 10){
println("i="+ i +", j="+j)
count += 1
}
println(count);
//例子: 打印小九九
for(i <- 1 until 10 ;j <- 1 until 10){
if(i>=j){
print(i +" * " + j + " = "+ i*j+" ")
}
if(i==j ){
println()
}
}
判断for循环
//可以在for循环中加入条件判断
for(i<- 1 to 10 ;if (i%2) == 0 ;if (i == 4) ){
println(i)
}
for循环与yidld
/*
yield 关键字返回一个集合(`for {子句} yield {变量或表达式}`,原来的集合不会被
改变,只会通过你的for/yield构建出一个新的集合。)
将 for 循环的返回值作为一个变量存储
var retVal = for{ var x <- List
if condition1; if condition2...
}yield x
*/
object Test {
def main(args: Array[String]) {
var a = 0;
val numList = List(1,2,3,4,5,6,7,8,9,10);
// for 循环
var retVal = for{ a <- numList
if a != 3; if a < 8
}yield a
// 输出返回值
for( a <- retVal){
println( "Value of a: " + a );
}
}
}
while循环(两种方式), while(){},do {}while()
//将for中的符合条件的元素通过yield关键字返回成一个集合
val list = for(i <- 1 to 10 ; if(i > 5 )) yield i
for( w <- list ){
println(w)
}
/**
* while 循环
*/
var index = 0
while(index < 100 ){
println("第"+index+"次while 循环")
index += 1
}
index = 0
do{
index +=1
println("第"+index+"次do while 循环")
}while(index <100 )
Scala 使用
def
关键字告诉编译器这是一个方法。
返回值类型与返回值
- 在参数后面加一个冒号和类型来显式地指定返回类型。
- 方法可以写返回值的类型也可以不写,会自动推断,但是如果有显式的Return有时候不能省略,必须写,
- Scala 中函数有返回值时,可以写 return ,也可以不写 return ,不写 return 时会把函数中最后一行当做结果返回。
- 如果去掉方法体前面的等号,那么这个方法返回类型必定是 Unit 的。scala可以把任意类型转
换为 Unit 。
- 假设,函数里面的逻辑最后返回了一个 string ,那么这个返回值会被转换成 Unit ,原本逻辑的值
会被丢弃
。def functionName ([参数列表]) : [return type] = { function body return [expr] } def method1 (a: Int , b: Int ) : Unit = { println(a+b) } method1(1,1) def method2 (a : Int , b : Int) = a+b println(method2(1,2)) def method3(s: String) { return s } println(method3("m3"))
Scala的函数是基于Function家族,0-22,一共23个Function Trait可以被使用,数字代表了Funtcion的入参个数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y8p7wBCK-1658889492340)(C:\Users\58266\AppData\Roaming\Typora\typora-user-images\1657872025749.png)]
Java里只有方法都能适应一切需求,那scala又提出函数的概念肯定有意义。
函数可以直接赋值给变量,可以让函数很方便的传递
var f1 = (s: String) => {
println("hi1 " + s);
}
var f2 = (s: String) => {
println("hi2 " + s);
}
对于java来说,方法和函数是等价的,或者
说没有函数这个概念。而对于scala
,这两者似乎有一个较为明确的边界
Scala有方法与函数,语义上有很小的区别
Scala 方法是类的一部分,而函数是一个对象 对象的引用可以赋值给一个变量。换句话来说在类中定义的函数即是方法
。
Scala 中的函数则是一个完整的对象
,Scala 中的函数其实就是继承了 Trait
的类的对象。Scala 中使用 val
语句可以定义函数,def
语句定义方法。
def m(x: Int) = x + 3
val f = (x: Int) => x + 3
方法与函数的区别:
当函数定义在类中,就表示方法,其他的都称为函数
函数可以作为一个参数传入到方法中,而方法就不行
在Scala中无法直接操作方法,如果要操作方法,必须先将其转换成函数,
通常情况下,编译器会自动将方法转换成函数
val f = m _ //
表示将m 方法转换为函数
def msum(nums: Array[Int]) = { var sum = 0; for (num <- nums) { sum += num; } sum } var fsum = msum _ println(fsum(Array[Int](1, 2, 3, 4, 5)));
- `在需要函数的地方,如果传递一个方法,会自动进行ETA展开(把方法转换为函数)` ```scala def main(args: Array[String]): Unit = { method02(method01, "libai") } def method01(s: String) = { println("hi4 " + s); } def method02(fun: String => Unit, str: String) = { fun(str); }
函数必须要有参数列表,而方法可以没有参数列表
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m0G6I3W9-1658889492340)(资源/1657891719536.png)]
- 如果我们直接把一个方法赋值给变量会报错,(Missing arguments for method
method01(Int,Int))- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CMhC4o0c-1658889492341)(资源/1657891733346.png)]
闭包是一个
函数
,返回值依赖于声明在函数外部的一个或多个变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数
//匿名的函数,函数体内有一个变量 i,它作为函数的一个参数。
val multiplier = (i:Int) => i * 10
//multiplier 中有两个变量:i 和 factor。其中的一个 i 是函数的形式参数
//multiplier 函数被调用时,i 被赋予一个新的值。然而,factor不是形式参数,而是自由变量
var factor = 3
val multiplier = (i:Int) => i * factor
//函数变量 multiplier 成为一个"闭包",因为它引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。
object Test {
def main(args: Array[String]) {
println( "muliplier(1) value = " + multiplier(1) )
println( "muliplier(2) value = " + multiplier(2) )
}
var factor = 3
val multiplier = (i:Int) => i * factor
}
String 是一个不可变的对象
,所以该对象不可被修改。这就意味着你如果修改字符串就会产生一个新的字符串对象。String Builder
类创建一个可以修改
的字符串。//创建字符串
var str1 = "Hello World!";
var str2:String = "Hello World!";
//创建可变字符串
val buf = new StringBuilder;
buf += 'a'
buf ++= "bcdef"
println( "buf is : " + buf.toString );
Scala 语言中提供的数组是用来存储固定大小的同类型元素
,数组对于每一门编辑应语言来说都是重要的数据结构之一。
数组的第一个元素索引为0,最后一个元素的索引为元素总数减1。
创建数组的两种方式:
/**
* 创建数组两种方式:
* 1.new Array[String](3)
* 2.直接Array
*/
//创建类型为Int 长度为3的数组
val arr1 = new Array[Int](3)
arr1(0) = 100
arr1(1) = 200
arr1(2) = 300
//创建String 类型的数组,直接赋值
val arr2 = Array[String]("s100","s200","s300")
遍历的两种方式
/**
* 遍历两种方式
*/
for(i <- arr1){
println(i)
}
arr1.foreach(i => {
println(i)
})
for(s <- arr2){
println(s)
}
arr2.foreach {
x => println(x)
}
//最简单写法
arr2.foreach(println)
创建二维数组
/**
* 创建二维数组和遍历
*/
val arr3 = new Array[Array[String]](3)
arr3(0)=Array("1","2","3")
arr3(1)=Array("4","5","6")
arr3(2)=Array("7","8","9")
for(i <- 0 until arr3.length){
for(j <- 0 until arr3(i).length){
print(arr3(i)(j)+" ")
}
println()
}
可变长度数组
//需要引入相应包,mutable就是可变,immutable就是不可变
import scala.collection.mutable.ArrayBuffer
val arr = ArrayBuffer[String]("a","b","c")
arr.append("hello","scala")//添加多个元素
arr.+=("end")//在最后追加元素
arr.+=:("start")//在开头添加元素
arr.foreach(println)
数组复杂应用
//合并数组
var c = Array(1,2,3)
var b = Array(4,5,6)
b++c
//合并数组 并将右边的类型作为最终结果返回.最后c为LinkList类型
val a = List(1,2)
val b = scala.collection.mutable.LinkedList(3,4)
val c = a ++: b
//在数组前添加一个元素,数组在哪冒号在哪
val k = 0
val a = List(1,2)
val c = k +: a // c中的内容是 (0,1,2)
val d = a :+ k // d中的内容是 (1,2,0)
//对数组中所有的元素进行相同的操作
val a = List(1,2,3,4)
val c = (10 /: a)(_+_) // 1+2+3+4+10
val d = (10 /: a)(_*_) // 1*2*3*4*10
println("c:"+c) // c:20
println("d:"+d) // d:240
val a = List(1,2,3,4)
val b = new StringBuilder("678")
val c = a.addString(b) // c中的内容是 1234
val d = a.addString(b,",") // 连接字符串时每个元素按分隔符隔开
val e = a.addString(b,"shou",",","wei") // 在首尾各加一个字符串,并指定sep分
隔符
//取出指定索引处得元素
arr.apply(index)
//判断两个对象是否可以进行比较
arr.canEqual()
//创建一个副本,不是引用,是深拷贝
val chars = Array('a','b','c')
val newchars = chars.clone()
任意多的辅助构造器
(auxiliary constructor)。辅助构造器的名称为thisgetter和setter方法
@BooleanBeanProperty
注解增加Java方式的getter和setter在Scala中,你几乎可以在任何语法结构中内嵌任何语法结构。你可以在函数中定义函数,在类中定义类。
在Scala中,每个实例都有它自己的Member类,就和它们有自己的members字段一样
要构建一个新的内部对象,你只需要简单的new这个类名:new chatter.Member。
class Network {
private val members = new ArrayBuffer[Member]
def join(name: String) = {
val m = new Member(name)
members += m
m
}
class Member(val name: String) {
val contacts = new ArrayBuffer[Member]
}
}
val chatter = new Network
val fred = chatter.join("Fred")
val wilma = chatter.join("Wilma")
fred.contacts += wilma //OK
val barney = myFace.join("Barney") // 类型为myFace .Member
fred.contacts += barney // 不可以这样做,不能将一个myFace.Member添加到
chatter.Member元素缓冲当中
object的由来
scala 中的 object 是单例对象,相当于 java 中的工具类,可以看成是定义静态的方法的类。object 不可以传参数。
extends
关键字来继承一个类。Scala 只允许继承一个
父类。
override
修饰符。定义属性和方法的实现
。继承的多个trait中如果有同名的方法和属性,必须要在类中使用 override 重新定义。
trait 中不可以传参数
trait Read {
val readType = "Read"
val gender = "m"
def read(name:String){
println(name+" is reading")
}
}
trait Listen {
val listenType = "Listen"
val gender = "m"
def listen(name:String){
println(name + " is listenning")
}
}
class Person() extends Read with Listen{
override val gender = "f"
}
object test {
def main(args: Array[String]): Unit = {
val person = new Person()
person.read("zhangsan")
person.listen("lisi")
println(person.listenType)
println(person.readType)
println(person.gender)
}
}
object test {
def main(args: Array[String]): Unit = {
val p1 = new Point(1,2)
val p2 = new Point(1,3)
println(p1.isEqual(p2))
println(p1.isNotEqual(p2))
}
}
trait Equal{
def isEqual(x:Any) :Boolean
def isNotEqual(x : Any) = {
!isEqual(x)
}
}
class Point(xx:Int, yy:Int) extends Equal {
val x = xx
val y = yy
def isEqual(p:Any) = {
if(p.isInstanceOf[Point]){//判断p是否为[XX]类的实例
val point : Point = p.asInstanceOf[Point]//将p转换为[XX]类的实例
x == point.x && y == point.y
}else
false
}
}
特征也可以有构造器,由字段的初始化和其他特征体中的语句构成。这些语句在任何混入该特征的对象在构造时都会被执行。
构造器的执行顺序:
构造器的顺序是类的线性化的反向。线性化是描述某个类型的所有超类型的一种技术规格。
private,protected,public
。用 private 关键字修饰,带有此标记的成员仅在包含了成员定义的类或对象内部可见,同样的规则还适用内部类。
(new Inner).f( ) 访问不合法是因为 f 在 Inner 中被声明为 private,而访问不在类 Inner 之内。
但在 InnerMost 里访问 f 就没有问题的,因为这个访问包含在 Inner 类之内。
Java中允许这两种访问,因为它允许外部类访问内部类的私有成员。
如果字段是私有的,则getter和setter方法也是私有的
如果字段是val,则只有getter方法被生成
如果你不需要任何getter或setter,可以将字段声明为 private[this]
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正确
}
}
(new Inner).f() //错误
}
在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许保护成员在定义了该成员的的类的子类中被访问。
在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里
的其他类也可以进行访问。
package p{
class Super{
protected def f() {println("f")}
}
class Sub extends Super{
f()
}
class Other{
(new Super).f() //错误
}
}
Scala 中,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。
编程中可以通过键盘输入语句来接收用户输入的数据。(回顾 java 中的 scanner 对象)
在 scala 中只需要导入对应的包,比 java 还要简单不需要实例化对象。
import scala.io.StdIn
object Test {
def main(args: Array[String]): Unit = {
println("请输入姓名")
val name = StdIn.readLine()
println("请输入年龄")
val age = StdIn.readInt()
printf("您输入的姓名是%s,年龄是%d",name,age)
}
}
如上述代码所示, printf
的用法和 java 中一样为格式化输出。使用时注意规范即可。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qWWk4XF-1658889492341)(资源/1657958011926.png)]
表示函数的返回类型(Function Type)
匿名函数
匿名函数定义, 左边是参数 右边是函数实现体
var function0 = () => Math.random()
var function1 = (x: Int) => Math.random()
case语句
val x = 10;
val y = 20;
val max = x > y match {
case true => x
case false => y
By-Name Parameters(传名参数)
传名参数在函数调用前表达式不会被求值,而是会被包裹成一个匿名函数作为函数参数传递下
去
ef doubles(x: => Int) = {
println("Now doubling " + x)
println("Now doubling " + x)
x * 2
}
def f(x: Int): Int = {
println(s"Calling f($x)")
x
}
作为通配符,类似Java中的*. 如 import scala.math._
:_*作为一个整体,告诉编译器你希望将某个参数当做参数序列处理
//将 1 to 5 当做参数序列处理
val s = sum(1 to 5:_*)
指代一个集合中的元素
//在一个Array a中筛选出偶数, 并乘以2,可以用以下这个办法
a.filter(_%2==0).map(2*_)
//要对缓冲数组ArrayBuffer b排序,可以这样:
val bSorted = b.sorted(_)
使用模式匹配可以用来获取元组的组员,例如
下划线_代表的是某一类型的默认值.
var name = _ (前提必须是变量var 不能是val)
对于Int来说,它的默认值为0
对于Double来说,它的默认值是0.0
对于引用类型来说,它是null.
:: 该方法被称为cons,意为构造
,向队列的头部追加数据,创造新的列表。用法为 x::list ,其
中 x 为加入到头部的元素,无论 x 是列表与否,它都只将成为新生成列表的第一个元素,也就是说
新生成的列表长度为list的长度+1(btw, x::list 等价于 list.::(x) )
:+
和 +:
两者的区别在于 :+ 方法用于在尾部追加元素, +: 方法用于在头部追加元素,和 :: 很类似,但是 :: 可以用于pattern match ,而 +: 则不行. 关于 +: 和 :+ ,只要记住冒号永远靠近集合类型
就OK了。
::: 该方法只能用于连接两个List类型的集合
。
++ 该方法用于连接两个集合, **list1++list2
** 。
scala> "A"::"B"::Nil
res0: List[String] = List(A, B)
scala> "A"+:"B"+:Nil
res1: List[String] = List(A, B)
scala> Nil:+"A":+"B"
res2: List[String] = List(A, B)
scala> res0 ++ res1
res3: List[String] = List(A, B, A, B)
scala> res0 ::: res1
res4: List[String] = List(A, B, A, B)
scala> res0 :: res1
res5: List[java.io.Serializable] = List(List(A, B), A, B)
传值调用(call-by-value):
先计算参数表达式的值,再应用到函数内部;
传名调用(call-by-name):
将未计算的参数表达式直接应用到函数内部
一般情况下函数调用参数,就按照函数定义时的参数顺序一个个传递。但是我们也可以通过指定函数参数名,并且不需要按照顺序向函数传递参数
object Test {
def main(args: Array[String]) {
printInt(b=5, a=7);
}
def printInt( a:Int, b:Int ) = {
println("Value of a : " + a );
println("Value of b : " + b );
}
}
自己调自己
必须有程序的出口
/**
* 递归函数 10的阶乘
*
*/
object Test {
def main(args: Array[String]) {
for (i <- 1 to 10)
println(i + " 的阶乘为: = " + factorial(i) )
}
def factorial(n: BigInt): BigInt = {
if (n <= 1)
1
else
n * factorial(n - 1)
}
}
Scala 可以为函数参数指定默认参数值,使用了默认参数
/**
* 包含默认参数值的函数
* 注意:
* 1.默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值
* 2.如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称
*/
def fun3(a :Int = 10,b:Int) = {
println(a+b)
}
fun3(b=2)
可以在 Scala 函数内定义函数,定义在函数内的函数称之为局部函数。
/**
* 嵌套函数
* 例如:嵌套函数求5的阶乘
*/
def fun5(num:Int)={
def fun6(a:Int,b:Int):Int={
if(a == 1){
b
}else{
fun6(a-1,a*b)
}
}
fun6(num,1)
}
println(fun5(5))
/**
* 偏应用函数
*/
def log(date :Date, s :String)= {
println("date is "+ date +",log is "+ s)
}
val date = new Date()
log(date ,"log1")
log(date ,"log2")
log(date ,"log3")
//想要调用log,以上变化的是第二个参数,可以用偏应用函数处理
val logWithDate = log(date,_:String)
logWithDate("log1")
logWithDate("log2")
logWithDate("log3")
高阶函数(Higher-Order Function)就是操作其他函数的函数
。
bject Test {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
// 函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
/**
* 高阶函数
* 函数的参数是函数 或者函数的返回是函数 或者函数的参数和返回都是函数
*/
//函数的参数是函数
def hightFun(f : (Int,Int) =>Int, a:Int ) : Int = {
f(a,100)
}
def f(v1 :Int,v2: Int):Int = {
v1+v2
}
println(hightFun(f, 1))
//函数的返回是函数
//1,2,3,4相加
def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
def f2 (v1: Int,v2:Int) :Int = {
v1+v2+a+b
}
f2
}
println(hightFun2(1,2)(3,4))
//函数的参数是函数,函数的返回是函数
def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
f
}
println(hightFun3(f)(100,200))
println(hightFun3((a,b) =>{a+b})(200,200))
//以上这句话还可以写成这样
//如果函数的参数在方法体中只使用了一次 那么可以写成_表示
println(hightFun3(_+_)(200,200))
将原来接受两个参数的函数变成新的接受一个参数的函数的过程
。/**
* 柯里化函数
*/
def fun7(a :Int,b:Int)(c:Int,d:Int) = {
a+b+c+d
}
println(fun7(1,2)(3,4))//执行完1+2得出3之后继续往下作为函数执行3+3+4最终求出结果10
scala.collection 中的所有集合。这些都是高级抽象类或特征,通常具有可变和不可变的实现。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gIh1AJjr-1658889492342)(资源/1658129058916.png)]
scala.collection.immutable
中的所有集合。不变
的
不会被改变。但仍可以进行模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CX92H1tY-1658889492342)(资源/1658129141153.png)]
scala.collection.mutable
中的所有集合。可变
的
可以在适当的地方被更新或扩展,可以修改,添加,移除一个集合的元素。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xYR8tSFd-1658889492342)(资源/1658129205837.png)]
grouped
方法返回元素的增量分块sliding
方法生成一个滑动元素的窗口。Seq trait用于表示序列。序列,指的是一类具有一定长度的可迭代访问的对象,其中每个元素均带有一个从0开始计数的固定索引位置。
常见操作
- 索引和长度的操作 (apply、isDefinedAt、length、indices、lengthCompare)
索引检索操作
(indexOf、lastIndexOf、indexofSlice、lastIndexOfSlice、indexWhere、
lastIndexWhere、segmentLength、prefixLength)
- 返回等于给定值或满足某个谓词的元素的索引。
加法运算
(+:,:+,padTo)
- 在序列的前面或者后面添加一个元素并作为新序列返回。
更新操作
(updated,patch)
- 替换原序列的某些元素并作为一个新序列返回。
排序操作
(sorted, sortWith, sortBy)
- 对序列元素进行排序。
反转操作
(reverse, reverseIterator, reverseMap)
- 将序列中的元素以相反的顺序排列。
比较
(startsWith, endsWith, contains, containsSlice, corresponds)
- 对两个序列进行比较,或者在序列中查找某个元素。
多集操作
(intersect, diff, union, distinct)
- 对两个序列中的元素进行类似集合的操作,或者删除重复元素
trait Seq 具有两个subtrait LinearSeq和IndexedSeq。
//索引和长度
scala> val a = List(1,2,3,4,5,6)
a: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> a isDefinedAt 0
res0: Boolean = true
scala> val b = List(2,3,4)
b: List[Int] = List(2, 3, 4)
scala> a.lengthCompare(b)
res1: Int = 1
scala> a.indices
res2: scala.collection.immutable.Range = Range 0 until 6
//索引搜索
scala> a.lastIndexOf(7)
res0: Int = -1
scala> a.lastIndexOf(1)
res1: Int = 0
scala> val b = List(2,3,4)
b: List[Int] = List(2, 3, 4)
// 加法
scala> a.padTo(10,1)
res12: List[Int] = List(1, 2, 3, 4, 5, 6, 1, 1, 1, 1)
//更新
scala> a.patch(3,List("a","b"),1)
res14: List[Any] = List(1, 2, 3, a, b, 5, 6)
scala> a.updated(0,2)
res16: List[Int] = List(2, 2, 3, 4, 5, 6)
//排序
scala> val a = List(2,1,5,3,6,0)
a: List[Int] = List(2, 1, 5, 3, 6, 0)
scala> a.sorted
res23: List[Int] = List(0, 1, 2, 3, 5, 6)
//多集操作
scala> a.intersect(b)
res38: List[Int] = List(2, 3)
scala> a.diff(b)
res40: List[Int] = List(1, 5, 6, 0)
不包含重复元素
的可迭代对象。键值对结构
。Scala的Predef类提供了隐式转换,允许使用另一种语法:key ->value 代(key,value)类似于数组
,它们所有元素的类型都相同
,但是它们也有所不同:
列表是不可变
的,值一旦被定义了就不能改变,递归的结构
Nil
和 ::
Nil 是 长度为0的List
。head
返回列表第一个元素tail
返回一个列表,包含除了第一元素之外的其他元素isEmpty
在列表为空时返回true// 字符串列表
val site: List[String] = List("Runoob", "Google", "Baidu")
// 整型列表
val nums: List[Int] = List(1, 2, 3, 4)
// 空列表
val empty: List[Nothing] = List()
// 二维列表
val dim: List[List[Int]] =
List(
List(1, 0, 0),
List(0, 1, 0),
List(0, 0, 1)
)
// 字符串列表
val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil))
// 整型列表
val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
// 空列表
val empty = Nil
// 二维列表
val dim = (1 :: (0 :: (0 :: Nil))) ::
(0 :: (1 :: (0 :: Nil))) ::
(0 :: (0 :: (1 :: Nil))) :: Nil
// 重复数据列表
val site = List.fill(3)("hello")
// 通过给定的函数创建
val squares = List.tabulate(6)(n => n * n)
println( "一维 : " + squares )
// 创建二维列表
val mul = List.tabulate( 4,5 )( _ * _ )
println( "多维 : " + mul )
for 与 foreach
两种方式
//遍历
list.foreach { x => println(x)}
list.foreach { println}
filter
:过滤元素
count
:计算符合条件的元素个数
map
:对元素操作
flatmap
:压扁扁平,先map再flat
//filter
val list1 = list.filter { x => x>3 }
list1.foreach { println}
//count
val value = list1.count { x => x>3 }
println(value)
//map
val nameList = List(
"hello beijing",
"hello shanghai",
"hello guangzhou"
)
val mapResult:List[Array[String]] = nameList.map{ x => x.split(" ") }
mapResult.foreach{println}
//flatmap
val flatMapResult : List[String] = nameList.flatMap{ x => x.split(" ") }
flatMapResult.foreach { println }
import scala.collection.mutable.ListBuffer
val listBuffer = ListBuffer[Int](1,2,3,4,5)
listBuffer.append(6,7,8,9) //追加元素
listBuffer.+=(10) //在后面追加元素
listBuffer.+=:(100) //在开头追加元素
listBuffer.foreach(println)
- Scala Set(集合)是没有重复的对象集合,所有的元素都是唯一的。
- Scala 集合分为可变的和不可变的集合。
默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用
scala.collection.mutable.Set
包。- Scala集合有三个基本操作:
head
返回集合第一个元素tail
返回一个集合,包含除了第一元素之外的其他元素isEmpty
在集合为空时返回true
//创建
val set1 = Set(1,2,3,4,4)
val set2 = Set(1,2,5)
同样两种方式 for
, foreach
//遍历
set1.foreach { println}
for(s <- set1){
println(s)
}
println("*******")
交集: intersect , &
差集: diff , &~
子集: subsetOf
最大: max
最小: min
转成数组: toList
转成字符串: mkString
/**
* 方法举例
*/
//交集
val set3 = set1.intersect(set2)
set3.foreach{println}
val set4 = set1.&(set2)
set4.foreach{println}
println("*******")
//差集
set1.diff(set2).foreach { println }
set1.&~(set2).foreach { println }
//子集
set1.subsetOf(set2)
//最大值
println(set1.max)
//最小值
println(set1.min)
println("****")
//转成数组,list
set1.toArray.foreach{println}
println("****")
set1.toList.foreach{println}
//mkString
println(set1.mkString)
println(set1.mkString("\t"))
import scala.collection.mutable.Set
val set = Set[Int](1,2,3,4,5)
set.add(100)
set.+=(200)
set.+=(1,210,300)
set.foreach(println)
Map(1 –>"shanghai")
键 -> 值的对应关系创建Map((1,"shanghai"))
元组的形式(key,value)创建 map 时,相同的 key 被后面的相同的 key 顶替掉,只保留一个。
// 空哈希表,键为字符串,值为整型
var map1:Map[Char,Int] = Map()
val map2 = Map(
"1" -> "shanghai",
2 -> "shanghai",
(3,"beijing")
)
//获取值
println(map.get("1").get)
val result = map.get(8).getOrElse("no value")
println(result)
两种方式:for 与 foreach
//map遍历
for(x <- map){
println("====key:"+x._1+",value:"+x._2)
}
map.foreach(f => {
println("key:"+ f._1+" ,value:"+f._2)
})
//遍历key
val keyIterable = map.keys
keyIterable.foreach { key => {
println("key:"+key+", value:"+map.get(key).get)
} }
println("---------")
//遍历value
val valueIterable = map.values
valueIterable.foreach { value => {
println("value: "+ value)
} }
//合并map
val map1 = Map(
(1,"a"),
(2,"b"),
(3,"c")
)
val map2 = Map(
(1,"aa"),
(2,"bb"),
(2,90),
(4,22),
(4,"dd")
)
map1.++(map2).foreach(println)
**注意:**合并 map 会将 map 中的相同 key 的 value 替换
filter
:过滤,留下符合条件的记录count
:统计符合条件的记录数contains
: map 中是否包含某个 keyexist
:符合条件的记录存在与否import scala.collection.mutable.Map
//如果你想要添加一个原来的map中没有的value类型,要么就手动显示[String,Any]
val map = Map[String,Any](("name", "lisi"),("money",200))
map+=("age"->18)//单个添加
map+=("age1"->18,"age2"->18,"age3"->18)//多个添加
map-=("age")//删除直接针对key值。map.remove("age")
大体与列表一样,不同的是元组可以包含不同类型的元素
。元组的值是通过将单个的值包含在圆括号中构成的。
- val tuple1 = new Tuple(1)
- val tuple2 = Tuple2(1,2)
- val tuple3 =(1,2,3)
- 取值用 ._X 可以获取元组中的值
注意:tuple最多支持22个参数。
//创建,最多支持22个
val tuple = new Tuple1(1)
val tuple2 = Tuple2("zhangsan",2)
val tuple3 = Tuple3(1,2,3)
val tuple4 = (1,2,3,4)
val tuple18 = Tuple18(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
val tuple22 = new
Tuple22(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
//使用
println(tuple2._1 + " "+tuple2._2)
val t = Tuple2((1,2),("zhangsan","lisi"))
println(t._1._2)
tuple.productIterator
得到迭代器,进而实现遍历。迭代器只能使用一次,下次还想遍历就需要构建一个新的 iterator 。//遍历
val tupleIterator = tuple22.productIterator
while(tupleIterator.hasNext){
println(tupleIterator.next())
}
/**
* 方法
*/
//翻转,只针对二元组
println(tuple2.swap)
//toString
println(tuple3.toString())
val myMap: Map[String, String] = Map("key1" -> "value")
val value1: Option[String] = myMap.get("key1")
val value2: Option[String] = myMap.get("key2")
println(value1) // Some("value1")
println(value2) // None
getOrElse()
方法来获取元组中存在的元素或者使用其默认的值val a:Option[Int] = Some(5)
val b:Option[Int] = None
println("a.getOrElse(0): " + a.getOrElse(0) )
println("b.getOrElse(10): " + b.getOrElse(10) )
isEmpty()
方法来检测元组中的元素是否为 Noneval a:Option[Int] = Some(5)
val b:Option[Int] = None
println("a.isEmpty: " + a.isEmpty )
println("b.isEmpty: " + b.isEmpty )
统计一个数组中每个单词出现的次数
def main(args: Array[String]): Unit = {
//定义一个数组
val strings: Array[String] = Array[String]("Hello Word", "Hello Moto",
"Hello Word")
//正常版
list.flatMap((ele: String) => {
ele.split(" ")
}).map((ele: String) => {
new Tuple2(ele, 1)
}).groupBy((ele: (String, Int)) => {
ele._1
}).mapValues((list: List[(String, Int)]) => {
list.size
}).toList.sortBy((tuple: (String, Int)) => {
tuple._2
}).foreach(println)
//简写模式
strings.flatMap(_.split(" ")).map((_,
1)).groupBy(_._1).mapValues(_.size).toList.sortBy(_._2).foreach(println)
}
- Scala 提供了强大的模式匹配机制,应用也非常广泛。
- 一个模式匹配包含了一系列备选项,每个都开始于关键字
case
。- 每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。
object HelloMatch {
def main(args: Array[String]): Unit = {
val tuple = Tuple6(1, 2, 3f, 4, "abc", 55d)
val tupleIterator = tuple.productIterator
while (tupleIterator.hasNext) {
matchTest(tupleIterator.next())
}
}
/**
* 注意点:
* 1.模式匹配不仅可以匹配值,还可以匹配类型
* 2.模式匹配中,如果匹配到对应的类型或值,就不再继续往下匹配
* 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default
*/
def matchTest(x: Any) = {
x match {
case 1 => println("result is 1")
case 2 => println("result is 2")
case 3 => println("result is 3")
case 4 => println("result is 4")
case x: Int => println("type is Int")
case x: String => println("type is String")
case x: Double => println("type is Double")
case _ => println("no match")
}
}
}
def main(args: Array[String]): Unit = {
println(pf(1))
println(pf(6))
println(pf(true))
}
def pf: PartialFunction[AnyVal, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
case i: Int => "Int"
case i: Double => "Int"
case _ => "Other"
}
isDefinedAt
: 这个函数的作用是判断传入来的参数是否在这个偏函数所处理的范围内。
def main(args: Array[String]): Unit = {
println(pf.isDefinedAt(1))
println(pf.isDefinedAt(4))
}
def pf: PartialFunction[AnyVal, String] = {
case 1 => "One"
case 2 => "Two"
case 3 => "Three"
}
orElse
: 将多个偏函数组合起来使用,效果类似case语句。
def main(args: Array[String]): Unit = {
println(pf(1))
}
def onePf: PartialFunction[Int, String] = {
case 1 => "One"
}
def twoPf: PartialFunction[Int, String] = {
case 2 => "Two"
}
def threePf: PartialFunction[Int, String] = {
case 3 => "Three"
}
def pf = onePf orElse twoPf orElse threePf
andThen
: 相当于方法的连续调用,比如g(f(x))。
def main(args: Array[String]): Unit = {
var pf12 = onePf andThen twoPf
println(pf12(1))
}
def onePf: PartialFunction[Int, String] = {
case 1 => "string"
}
def twoPf: PartialFunction[String, Double] = {
case "string" => 2.0
}
applyOrElse
:它接收2个参数,第一个是调用的参数,第二个是个回调函数。如果第一个调用的参数匹配,返回匹配的值,否则调用回调函数。
def main(args: Array[String]): Unit = {
println(onePf.applyOrElse(1, { num: Int => "more" }))
println(onePf.applyOrElse(2, { num: Int => "more" }))
}
def onePf: PartialFunction[Int, String] = {
case 1 => "one"
}
object Hello08040018 {
def main(args: Array[String]): Unit = {
val user: SysUser = SysUser("admin", "123456", "管理员")
user match {
case SysUser(uname, passwd, nickname) => println(uname, passwd,
nickname)
}
}
}
case class SysUser(uname: String, passwd: String, nickname: String)
def main(args: Array[String]): Unit = {
person("admin")
implicit val name1 = "Harry"
// implicit val name2 = "Potter"
person
}
//name为隐式参数
def person(implicit name: String) = println(name)
隐式转换函数是指在同一个作用域下面,一个给定输入类型并自动转换为指定返回类型的函数,这个函数和函数名字无关,和入参名字无关,只和入参类型以及返回类型有关。注意是同一个作用域。
隐式转换为目标类型:把一种类型自动转换到另一种类型
def main(args: Array[String]): Unit = {
hello("str")
hello(123)
hi("str")
hi(123)
}
def hello(param: String): Unit = {
println(param)
}
def hi(param: String): Unit = {
println(param)
}
implicit def typeConverter(param: Int): String = "yjxxt:" + param
implicit def boolean2String(param: Boolean): String = "Boolean:" + param
隐式转换调用类中本不存在的方法
class Person {
def learn(name: String) = println("正在学习【" + name + "】...")
}
object Converter {
implicit def learnView(b: Boy) = new Person
implicit def learnView(g: Girl) = new Person
}
class Boy
class Girl
object HelloImplicitView {
def main(args: Array[String]): Unit = {
import com.yjxxt.p0805.Converter._
val xiaoming = new Boy
xiaoming.learn("数学")
val xiaofang = new Girl
xiaofang.learn("数学")
}
}
简介
implicit
关键字修饰的类就是隐式类。若一个 变量A 没有某些方法或者某些变量时,而这个 变量A 可以调用某些方法或者某些变量时注意点
具体写法
class Rabbit(s:String){
val name = s
}
object Lesson_ImplicitClass {
implicit class Animal(rabbit:Rabbit){
val tp = "Animal"
def canFly() ={
println(rabbit.name +" can fly...")
}
}
def main(args: Array[String]): Unit = {
val rabbit = new Rabbit("rabbit")
rabbit.canFly()
println(rabbit.tp)
}
}
隐式参数
注意点
implicit
关键字必须放在隐式参数定义的开头具体写法
def main(args: Array[String]) {
Param.print("jack")("hello")
import Context._
Param.print("jack")
}
object Context {
implicit val ccc: String = "implicit"
}
object Param {
def print(content: String)(implicit prefix: String) {
println(prefix + ":" + content)
}
}
Actor Model 是用来编写并行计算或分布式系统的高层次抽象(类似 java 中的 Thread )让程序员不必为多线程模式下共享锁而烦恼。 Actors 将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors 分享状态,每个 Actors 有自己的世界观,当需要和其他 Actors 交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外 Actors 回复,也不必暂停,每个 Actors 有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
2.12版本后,actor彻底从scala中抽离了出来,所以我们在使用前需要引入相应的lib。
<dependency>
<groupId>com.typesafe.akkagroupId>
<artifactId>akka-actor_2.12artifactId>
<version>2.5.9version>
dependency>
ActorModel 是消息传递模型,基本特征就是消息传递
消息发送是异步的,非阻塞的
消息一旦发送成功,不能修改
隐式类的构造必须只有一个参数,同一个类,包对象,伴生对象中不能出现同类型构造的隐式类。
具体写法
class Rabbit(s:String){
val name = s
}
object Lesson_ImplicitClass {
implicit class Animal(rabbit:Rabbit){
val tp = "Animal"
def canFly() ={
println(rabbit.name +" can fly...")
}
}
def main(args: Array[String]): Unit = {
val rabbit = new Rabbit("rabbit")
rabbit.canFly()
println(rabbit.tp)
}
}
隐式参数
注意点
implicit
关键字必须放在隐式参数定义的开头具体写法
def main(args: Array[String]) {
Param.print("jack")("hello")
import Context._
Param.print("jack")
}
object Context {
implicit val ccc: String = "implicit"
}
object Param {
def print(content: String)(implicit prefix: String) {
println(prefix + ":" + content)
}
}
Actor Model 是用来编写并行计算或分布式系统的高层次抽象(类似 java 中的 Thread )让程序员不必为多线程模式下共享锁而烦恼。 Actors 将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors 分享状态,每个 Actors 有自己的世界观,当需要和其他 Actors 交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外 Actors 回复,也不必暂停,每个 Actors 有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。
2.12版本后,actor彻底从scala中抽离了出来,所以我们在使用前需要引入相应的lib。
<dependency>
<groupId>com.typesafe.akkagroupId>
<artifactId>akka-actor_2.12artifactId>
<version>2.5.9version>
dependency>