欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

Scala语法教程

时间:2023-05-11
第一章 Scala入门 1.1概述

Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的 静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。

1) Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。(多范式,就是多种编程方

法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法。)

2) Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有 的Java类库,实现两种语言的无缝对接。

3)Scala单作为一门语言来看,非常的简洁高效。

4)Scala在设计时,马丁·奥德斯基是参考了Java的设计思想,可以说Scala是源于Java,同时马丁·奥 德斯基也加入了自己的思想,将函数式编程语言的特点融合到JAVA中, 因此,对于学习过Java的同学, 只要在学习Scala的过程中,搞清楚Scala和Java相同点和不同点,就可以快速的掌握Scala这门语言。

1.2环境搭建

基于JDK1.8

下载scala2.12.11

配置scala环境变量

1.3代码编写

package chapter01class Student(name:String,info: Int) { def printInfo():Unit ={ println(name+" "+info+" "+Student.school) }}object Student{ val school:String = "河北农业大学"//伴生对象 def main(args: Array[String]): Unit = { val student = new Student("张三",20) student.printInfo() }}

Student$.class

package chapter01;public final class Student${ public static MODULE$; private final String school; static { new (); } public String school() { return this.school; } public void main(String[] args) { Student student = new Student("张三", 20); student.printInfo(); } private Student$() { MODULE$ = this; this.school = "河北农业大学"; }}

Student.java

package chapter01;import scala.Predef.;import scala.reflect.ScalaSignature;@ScalaSignature(bytes="0601}2Aa03070137!Aa0301B01B03%q030305#01t05t25!03$212510301"01(2125a0301"01.1725tD02#013r25YA02#01421251c01"0152135)dA1A0502YBaa1604!0223902"023507t03I$aB*uk22,g163606023305I1r[1qi2624b'M0201't010103050222)5t!CC01240325318-317b23t)"C0104B]f24VMZ0105]06lWr050231?92121$bt035Ii21a07060399ta0120:p_Rt24B012023033101&/323fM&2101%t0207'R2430N\41305y212201B5oM>04"!0523n052522"aA%oi061A(338jiz"2011326,!tI03!D01r2125120110130212521301101$03%01(/338u23:4w16F01/!ttr&03021%t!QK\5u033531F/363f]R04"!130424053101B#013202rM3407n\8m+05922aB:dQ>|G16I0105[06Lg160602/u!)1H03a01y05!21M]4t!rtRhF0503}I21Q!21:sCf04")public class Student{ private final String name; private final int info; public static void main(String[] paramArrayOfString) { Student..MODULE$.main(paramArrayOfString); } public static String school() { return Student..MODULE$.school(); } public void printInfo() { Predef..MODULE$.println(2 + this.name + " " + this.info + " " + Student..MODULE$.school()); } public Student(String name, int info) { }}

第二章 变量和数据类型 2.1 变量和常量

var 变量名 :变量类型 = 值

val 常量名 :常量类型 = 值

变量类型都可省略,编译器会自动推断

能使用常量的地方不用变量

(1) 声明变量时,类型可以省略

(2) 类型确定后不可以修改

(3) 变量声明时,必须有初始值

(4) 声明变量时,可以使用var和val,var可以变,val不可变

2.2 标识符的规范

以操作符开头,且只包含操作符(+ - * / # !等)

用反引号....包括的任意字符串,即使是 Scala 关键字(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

2.3 字符串

(1)字符串,通过+号连接 ,可以字符串乘法

(2)printf 用法:字符串,通过%传值。

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

var age="hello"println(s"${age}")var num = 2.3456println(f"The num is ${num}%.2f")//保留两位小数println(raw"The num is ${num}%.2f")//raw 输出原格式//三引号格式 可以换行写多行文本,保持原格式s"""""".stripMargin

2.4 键盘输入

StdIn 就是new Scanner

基本语法

StdIn.readLine()、StdIn.readShort()、StdIn.readDouble()

2.5 文件操作

def main(args: Array[String]): Unit = { //读取文件 Source.fromFile("src/main/resources/test.txt").foreach(print) //将数据写入文件 scala没有封装好的写入文件类库 使用Java io即可 val writer = new PrintWriter(new File("src/main/resources/test1.txt")) writer.write("hello scala from java writer") writer.close() }

2.6 数据类型

1)Scala中一切数据都是对象,都是Any的子类。

2)Scala中数据类型分为两大类:数值类型(AnyVal)、 引用类型(AnyRef),不管是值类型还是引用类型都是对象。

3)Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)

4)Scala中的StringOps是对Java中的String增强

5) Unit:对应Java中的void,用于方法返回值的位置,表 示方法没有返回值。Unit是一个数据类型,只有一个对象 就是()。Void不是数据类型,只是一个关键字

6) Null是一个类型,只有一个对象就是null。它是所有引用类型(AnyRef)的子类。

Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数

第三章 流程控制 3.1 if else

语法与java没有区别

但每个分支都可以返回值

返回的类型为分支代码块的最后一行内容

val age = StdIn.readInt() var result = if (age>18){ println("18") 15 } else{ "000" } println(result)

3.2 for

to unitl

区别就在于until没有右边界

for(i <- 1 to 3){ print(i + " ")}println()------------------------------------------------------for(i <- 1.to(3){ print(i + " ")}

底层是调用的方法

for (i <- Range(1,10)){}//不包含边界 Range为伴生对象for (i <- 1 until 10){}//底层就是上面

scala中的foreach循环

for (i <- Array(10,20,30))for (i <- List(10,20,30))for (i <- Set(10,20,30))

循环守卫

scala中没有continue

for (i <- 0 to 10 if i!=5){}

循环步长

for(i <- 1 to 3 by 2){}//步长不能为0

反转 reverse

for(i <- 1 to 3 reverse){}for(i <- 3 to 1 by -1){}

循环嵌套

for(i <- 1 to 3; j <- 1 to 3) { println(" i =" + i + " j = " + j)}//等价for (i <- 1 to 3) { for (j <- 1 to 3) { println("i =" + i + " j=" + j) }}

循环返回值

很少用

object TestFor { def main(args: Array[String]): Unit = { var res = for(i <-1 to 10) yield { i * 2 } println(res) }}输出结果:Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

3.3 while do

因为 while 中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免 的使用变量,而变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量 造成了影响,所以不推荐使用,而是推荐使用 for 循环。

与java语法相同

3.4 循环中断

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

import scala.util.control.Breaksimport scala.util.control.Breaks._def main(args: Array[String]): Unit = { Breaks.breakable( for (elem <- 1 to 10) { println(elem) if (elem == 5) Breaks.break()//break() } ) println("正常结束循环")}

第四章 函数式编程 4.1 函数和方法的区别

1)核心概念

(1)为完成某一功能的程序语句的集合,称为函数。

(2)类中的函数称之方法。

2)案例实操

(1)Scala 语言可以在任何的语法结构中声明任何的语法

(2)函数没有重载和重写的概念;方法可以进行重载和重写

(3)Scala 中函数可以嵌套定义

4.2 函数参数

(1)可变参数

(2)如果参数列表中存在多个参数,那么可变参数一般放置在最后

(3)参数默认值,一般将有默认值的参数放置在参数列表的后面

(4)带名参数

可变类似于python

def hello (*str): print(type(str))hello("sac","1")------------------------

def hello(string: String*)={ println(string) }println(hello("1","2"))----------------------------WrappedArray(1, 2)

默认值

def hello(string: String = "hello")={ println(string) }

带名参数

def hello(name,age)={ println(name+age)}hello(age=15,name="张三")

4.3 函数至简原则(重点)

函数至简原则:能省则省

(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值

(2)如果函数体只有一行代码,可以省略花括号

(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)

(4)如果有 return,则不能省略返回值类型,必须指定

(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用

(6)Scala 如果期望是无返回值类型,可以省略等号

(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

匿名函数 lambda表达式

4.4 匿名函数

没有名字的函数就是匿名函数。

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

def fun1(name:String): Unit ={ println(name) } val tmp = (name:String)=>{println(name)} def fun2(fun:String => Unit): Unit ={ fun("张三") } fun2(tmp)

(1)参数的类型可以省略,会根据形参进行自动的推导

fun2((name)=>{println(name)})

(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参 数超过 1 的永远不能省略圆括号。

fun2( name =>{println(name)})

(3)匿名函数如果只有一行,则大括号也可以省略

fun2( name => println(name))

(4)如果参数只出现一次,则参数省略且后面参数可以用_代替

x fun2( name => println(_))fun2( println(_))

离谱版

fun2(println)

4.5 函数高级

函数对象

def fun1(name:String): Unit ={ println(name)}val tmp = (name:String)=>{println(name)}def fun2(fun:String => Unit): Unit ={ fun("张三")}val f1 = fun2 _val f2: String => Unit= fun1

val f1 = fun2 _

也可以返回一个函数对象

函数赋值

def func1(s:String): Char=>(Int=>Boolean)={ def func2(c:Char): Int=>Boolean ={ def fun3(i:Int):Boolean ={ if(i==0&&c=='0'&&s=='0') true else false } fun3 } func2 }

函数柯里化

def func1(i:Int)(s:String)(c:Char):Boolean={ true}

4.6 闭包

闭包:函数式编程的标配

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包

def func1(s:String): Char=>(Int=>Boolean)={ def func2(c:Char): Int=>Boolean ={ def fun3(i:Int):Boolean ={ if(i==0&&c=='0'&&s=='0') true else false } fun3 } func2 }

当函数func1调用后弹出栈局部变量也会被释放,但fun3仍然可以访问到上层函数的局部变量

这是因为scala将局部变量创建了函数对象打成了包放在了堆内存里,

4.7 递归

def con(n:Int): Int = { if (n ==0) return 1 con(n-1) * n }//尾递归,节省栈空间,指针不用变化def con1(n:Int):Int = { @tailrec //该注解可检查尾递归是否正确 def loo(n:Int,sum:Int):Int = { if(n==0) return sum loo(n-1,sum * n) } loo(n,1)}

4.8 控制抽象

1)值调用:把计算后的值传递过去

object TestControl { def main(args: Array[String]): Unit = { def f = ()=>{ println("f...")10 } foo(f()) } def foo(a: Int):Unit = { println(a) println(a) }}

2)名调用:把代码传递过去

object TestControl { def main(args: Array[String]): Unit = { def f = ()=>{ println("f...") 10 } foo(f()) }//def foo(a: Int):Unit = { def foo(a: =>Int):Unit = {//注意这里变量 a 没有小括号了 println(a) println(a) }}输出结果:f...10f...10

自己定义while循环

def myWhile(flag: => Boolean): (=> Unit)=>Unit= { def dowhile(con: => Unit):Unit = { con if (flag) dowhile(con) } dowhile } var n=10 myWhile(n>=1){ println(n) n-=1 } }

4.9 懒加载

当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。

第 五 章 面向对象 5.1包说明(包语句)

Scala 有两种包的管理风格,一种方式和 Java 的包管理风格相同,每个源文件一个包(包 名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系,如 com.atguigu.scala。另一种风格,通过嵌套的风格表示层级关系,如下

package com{package atguigu{package scala{}}}

第二种风格有以下特点:

(1)一个源文件中可以声明多个 package

(2)子包中的类可以直接访问父包中的内容,而无需导包

5.2 包对象

Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对 应包下所有 class 和 object 的共享变量,可以被直接访问。

package object com{val sharevalue="share"def shareMethod()={}}

如采用嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象 与包声明在同一作用域中。

5.3 导包说明

1)和 Java 一样,可以在顶部使用 import 导入,在这个文件中的所有类都可以使用。
2)局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用
3)通配符导入:import java.util._
4)给类起名:import java.util.{ArrayList=>JL}
5)导入相同包的多个类:import java.util.{HashSet, ArrayList}
6)屏蔽类:import java.util.{ArrayList =>,}
7)导入包的绝对路径:new root.java.util.HashMap

Scala 中的三个默认导入分别是
import java.lang._
import scala._
import scala.Predef._

5.4 类和对象

定义类

[修饰符] class 类{

}不加修饰符默认为public,加上public会报错

一个scala文件可以定义多个类

class student{ //该注解默认生成set get @BeanProperty private var:String name = "1" //默认public 但底层都是private //假如想要属性为空 name = _ 相当于null 或0}

5.5 封装

Scala 中的 public 属性,底层实际为 private,并通过 get 方法(obj.field())和 set 方法 (obj.field_=(value))对其进行操作。所以 Scala 并不推荐将属性设为 private,再为其设置 public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射调用 getXXX 和 setXXX 方 法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX 和 setXXX 方法(通过 @BeanProperty 注解实现)。

在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通 过类似的修饰符达到同样的效果。但是使用上有区别。

(1)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。

(2)private 为私有权限,只在类的内部和伴生对象中可用。

(3)protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以 访问,同包无法访问。

(4)private[包名]增加包访问权限,包名下的其他类也可以使用

5.6 构造器

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

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

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

说明:

(1)辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分。

(2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

(3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明。

5.7 抽象类

(1)定义抽象类:abstract class Person{} //通过 abstract 关键字标记抽象类

(2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性

(3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法

继承&重写

(1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明 为抽象类

(2)重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。

(3)子类中调用父类的方法使用 super 关键字

(4)子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;

子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var。

因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写

5.8 单例对象(伴生对象)

1)基本语法 object Person{ val country:String=“China” }

2)说明

(1)单例对象采用 object 关键字声明

(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。

(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。

apply 方法

通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。

如果想让主构造器变成私有的,可以在()之前加上 private。

当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构 建对象时,调用的其实时伴生对象的 apply 方法。

5.9 特质(Trait)

就是java中的interfacewith来实现

基本语法

trait 特质名 { 主体}

Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法

当trait与类属性冲突时,需要重写属性,否则报错

scala都是动态绑定的

没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …

有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3

多个特质方法冲突

trait Ball { def describe(): String = { "ball" }}trait Color extends Ball { override def describe(): String = { "blue-" + super.describe() }}trait Category extends Ball { override def describe(): String = { "foot-" + super.describe() }}class MyBall extends Category with Color { override def describe(): String = { "my ball is a " + super.describe() }}object TestTrait { def main(args: Array[String]): Unit = { println(new MyBall().describe()) }}//输出结果//my ball isa blue-foot-ball

5.9 类型检查和转换

(1)obj.isInstanceOf[T]:判断 obj 是不是 T 类型。

(2)obj.asInstanceOf[T]:将 obj 强转成 T 类型。

(3)classOf 获取对象的类名。

class Person{}object Person { def main(args: Array[String]): Unit = { val person = new Person //(1)判断对象是否为某个类型的实例 val bool: Boolean = person.isInstanceOf[Person] if ( bool ) { //(2)将对象转换为某个类型的实例 val p1: Person = person.asInstanceOf[Person] println(p1) } //(3)获取类的信息 val pClass: Class[Person] = classOf[Person] println(pClass) }}

5.10 枚举类和应用类

枚举类:需要继承 Enumeration

应用类:需要继承 App

// 枚举类object Color extends Enumeration { val RED = Value(1, "red") val YELLOW = Value(2, "yellow") val BLUE = Value(3, "blue")}// 应用类object Test20 extends App { println("xxxxxxxxxxx");}

使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名

type myString = String

第六章 集合 6.1 可变与不可变

Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质。

对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两 个包

不可变集合:scala.collection.immutable

可变集合: scala.collection.mutable

Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而 不会对原对象进行修改。类似于 java 中的 String 对象

可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象

Array与String特殊,使用了隐式转换

Set、Map 是 Java 中也有的集合,Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,但和List有不同

for 循环有一个 1 to 3,就是 IndexedSeq 下的 Range ,String 也是属于 IndexedSeq

经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)

Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map 可以支持排序

IndexedSeq 和 LinearSeq 的区别:

IndexedSeq 是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集

LinearSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

6.2 遍历

定义

定义:val arr1 = new Array[Int](10)println(arr01.length) // 4 //(2)数组赋值 //(2.1)修改某个元素的值 arr01(3) = 10 //(2.2)采用方法的形式给数组赋值 arr01.update(0,1) //(3)遍历数组 //(3.1)查看数组 println(arr01.mkString(",")) //(3.2)普通遍历 for (i <- arr01) { println(i) } //(3.3)简化遍历 def printx(elem:Int): Unit = { println(elem) } arr01.foreach(printx) // arr01.foreach((x)=>{println(x)}) // arr01.foreach(println(_)) arr01.foreach(println) //(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组) println(arr01) val ints: Array[Int] = arr01 :+ 5 println(ints) }

第二种方式定义数组

val arr1 = Array(1, 2)

(1)在定义数组时,直接赋初始值

(2)使用 apply 方法创建数组对象

6.3 数组

val arr01 = ArrayBuffer[Any](3, 2, 5)arr01.+=(4)//(3.2)向数组最后追加数据arr01.append(5,6)//向指定的位置(0)插入数据arr01.insert(0,7,8)arr01.preappend(5,6)//删除指定下标元素arr.remove(0)//从下标开始删除多个arr.remove(1,3)arr1.toBuffer //不可变数组转可变数组arr2.toArray //可变数组转不可变数组//从数组中移除 1 元素arr -= 1 //指定分隔符遍历arr.mkString(", ")//返回 length长度的rangea.indices

ArrayBuffer 是有序的集合,增加元素使用的是 append 方法(),支持可变参数

多维数组

val arr = Array.ofDim[Double](3,4)//说明:二维数组中有三个一维数组,每个一维数组中有四个元素

6.4 列表

有顺序不能用构造器创建,底层是继承了一个抽象类

只能用apply

值不可改变,可添加

//apply方法创建var list = List(0,1)var list1 = Nil.::(1)var list2 = 1 :: 2 :: 3 :: Nil//两个类实现了List Nil空列表类 ::类 :: 方法会将元素添加到末尾并返回新的列表//列表追加列表 :: 会返回嵌套列表 不是想要的追加元素// ::: 此方法会合成一个完整的list 或者 ++ // ++ 会返回新的 ++=会覆盖第一个

可变列表

ListBuffer

可new 可apply

new ListBuffer[Int]()//不能提前定义长度ListBuffer(1,2)3 +=: 4 list += 25 += 25

6.4 集合

可变set与不可变set名字都一样,只是包名不同

set是特质,使用伴生对象的apply方法,无序

方法与list一致

val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)//(1)获取集合的头println(list1.head)//(2)获取集合的尾(不是头的就是尾)println(list1.tail)//(3)集合最后一个数据println(list1.last)//(4)集合初始数据(不包含最后一个)println(list1.init)//(5)反转println(list1.reverse)//(6)取前(后)n 个元素println(list1.take(3))println(list1.takeRight(3))//(7)去掉前(后)n 个元素println(list1.drop(3))println(list1.dropRight(3))//(8)并集println(list1.union(list2))//(9)交集println(list1.intersect(list2))//(10)差集println(list1.diff(list2))//(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进行拉链,多余的数据省略不用 嵌套的时Tuple2类型println(list1.zip(list2))//(12)滑窗list1.sliding(2, 5).foreach(println)

6.5 Map

Map("a" -> 1)var a :Map [String , String] = Map()map.get("a")//不会返回value 会返回 Some(1) 想要返回value .get().get//当没有key值时get会报异常 使用 getOrElse("c",0) //如果为null 赋值0//也可以map("a") 报异常map.put("a","b")//删除a 键值对map -= "a"println(map)map += "sczc" -> "s"map.update("scac","nu")map += (("1","1"))println(map)//合并mapmap ++= mutable.Map ("2"-> "2")println(map)

6.6 元组

//元组 最大只有22个元素 创建方式跟py一样 () 下标从一开始不可变//并不是Any类型的列表 每个元组长度都有一个单独类 Tuple1-22var tuple = ("1",1,2.1,true)println(tuple)//(1,1,2.1,true)//访问数据 tuple._number or tuple.produceElement(num)println(tuple._1)//迭代器遍历for (elem <- tuple.productIterator)println(elem)//嵌套元组var tuple2 = (1,2,(3,3))println(tuple2._3._1)

集合常用函数

//(1)求和println(list.sum)//(2)求乘积println(list.product)//(3)最大值println(list.max)//(4)最小值println(list.min)//(5)排序// (5.1)按照元素大小排序println(list.sortBy(x => x))// (5.2)按照元素的绝对值大小排序println(list.sortBy(x => x.abs))// (5.3)按元素大小升序排序println(list.sortWith((x, y) => x < y))// (5.4)按元素大小降序排序println(list.sortWith((x, y) => x > y))

(1)sorted 对一个集合进行自然排序,通过传递隐式的 Ordering

(2)sortBy 对一个属性或多个属性进行排序,通过它的类型。

(3)sortWith 基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。lamda表达式

集合计算高级函数

val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) val nestedList: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) val wordList: List[String] = List("hello world","hello atguigu", "hello scala") //(1)过滤 println(list.filter(x => x % 2 == 0)) //(2)转化/映射 println(list.map(x => x + 1)) //(3)扁平化 println(nestedList.flatten) //(4)扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten操作 println(wordList.flatMap(x => x.split(" "))) //(5)分组 println(list.groupBy(x => x % 2)) }

Reduce 方法

通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最 终获取结果。

val list = List(1,2,3,4) // 将数据两两结合,实现运算规则 val i: Int = list.reduce( (x,y) => x-y ) println("i = " + i) // 从源码的角度,reduce 底层调用的其实就是 reduceLeft //val i1 = list.reduceLeft((x,y) => x-y)

Fold 折叠:化简的一种特殊情况。

val list = List(1,2,3,4) // fold 方法使用了函数柯里化,存在两个参数列表 // 第一个参数列表为 : 零值(初始值) // 第二个参数列表为: 简化规则 // fold 底层其实为 foldLeft val i = list.foldLeft(1)((x,y)=>x-y) val i1 = list.foldRight(10)((x,y)=>x-y

多线程

(1 to 100).par.map() //会多个x

第七章 模式匹配

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

var result = operator match { case '+' => a + b case '-' => a - b case '*' => a * b case '/' => a / b case _ => "illegal"}

每个 case 中,不需要使用 break 语句,自动中断 case。

匹配类型

def describe(x: Any) = x match { case i: Int => "Int" case s: String => "String hello" case m: List[_] => "List" case c: Array[Int] => "Array[Int]" case someThing => "something else " + someThing }

匹配数组

scala 模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素 为 0 的数组。

val result = arr match { case Array(0) => "0" //匹配 Array(0) 这个数组 case Array(x, y) => x + "," + y //匹配有两个元素的数组,然后将将元素值赋给对应的 x,y case Array(0, _*) => "以 0 开头的数组" //匹配以 0 开头和数组 case _ => "something else" }

匹配列表

def main(args: Array[String]): Unit = { val list: List[Int] = List(1, 2, 5, 6, 7) list match { case first :: second :: rest => println(first + "-" + second + "-" + rest) case _ => println("something else") } }

变量声明时匹配

var first :: second :: three = List(121,2 ,3.5,6)println(s"$first $second")//for循环简化for((var1,var2) <- List((1,2),(3,5)))println(var1+" "+var2)//可以不考虑位置的值 var2换成_ 只遍历第一个值for((var1,_) <- List((1,2),(3,5)))println(var1)//指定位置特殊值 只遍历1开头的元组for((1,_) <- List((1,2),(3,5)))println(var1)

匹配对象及样例类

object User{ def apply(name: String, age: Int): User = new User(name, age) def unapply(user: User): Option[(String, Int)] = { if (user == null) None else Some(user.name, user.age) }}object TestMatchUnapply { def main(args: Array[String]): Unit = { val user: User = User("zhangsan", 11) val result = user match { case User("zhangsan", 11) => "yes" case _ => "no" } println(result) }}

当将 User(“zhangsan”, 11)写在 case 后时[case User(“zhangsan”, 11) => “yes”],会默 认调用 unapply 方法(对象提取器),user 作为 unapply 方法的参数,unapply 方法 将 user 对象的 name 和 age 属性提取出来,与 User(“zhangsan”, 11)中的属性值进行 匹配

case 中对象的 unapply 方法(提取器)返回 Some,且所有属性均一致,才算匹配成功, 属性不一致,或返回 None,则匹配失败。

样例类

case class Person (name: String, age: Int)

○1 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中 自动提供了一些常用的方法,如 apply、unapply、toString、equals、hashCode 和 copy。

○2 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例 类可以直接使用模式匹配,而无需自己实现 unapply 方法。

○3 构造器中的每一个参数都成为 val,除非它被显式地声明为 var(不建议这样做)

偏函数中的模式匹配(了解)

功能是返回输入的 List 集合的第二个元素

第八章 隐式转换

异常处理

def main(args: Array[String]): Unit = { try { var n= 10 / 0 }catch { case ex: ArithmeticException=>{ // 发生算术异常 println("发生算术异常") } case ex: Exception=>{ // 对异常处理 println("发生了异常 1") println("发生了异常 2") } }finally { println("finally") }}

用 throw 关键字,抛出一个异常对象。所有异常都是 Throwable 的子类型。throw 表 达式是有类型的,就是 Nothing

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

隐式函数

class MyRichInt(val self: Int) { def myMax(i: Int): Int = { if (self < i) i else self } def myMin(i: Int): Int = { if (self < i) self else i }}object TestImplicitFunction { // 使用 implicit 关键字声明的函数称之为隐式函数 implicit def convert(arg: Int): MyRichInt = { new MyRichInt(arg) }def main(args: Array[String]): Unit = { // 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐式转换。也称之为自动转换 println(2.myMax(6)) }}

隐式参数

普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。

(1)同一个作用域中,相同类型的隐式值只能有一个

(2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。

(3)隐式参数优先于默认参数

object TestImplicitParameter { implicit val str: String = "hello world!" def hello(implicit arg: String="good bey world!"): Unit = { println(arg) } def main(args: Array[String]): Unit = { hello }}

隐式类

隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶 级的。

object TestImplicitClass { implicit class MyRichInt(arg: Int) { def myMax(i: Int): Int = { if (arg < i) i else arg } def myMin(i: Int) = { if (arg < i) arg else i } } def main(args: Array[String]): Unit = { println(1.myMax(3)) }}

implicit var a = 1 def myTest():Unit = { println("---"+ implicitly[Int]) }

泛型

class MyList[+T]{ //协变 }

class MyList[-T]{ //逆变 }

class MyList[T] //不变

说明 协变:Son 是 Father 的子类,则 MyList[Son] 也作为 MyList[Father]的“子类”。

逆变:Son 是 Father 的子类,则 MyList[Son]作为 MyList[Father]的“父类”。

不变:Son 是 Father 的子类,则 MyList[Father]与 MyList[Son]“无父子关系”。

泛型上下限

Class PersonList[T <: Person]{ //泛型上限 }

Class PersonList[T >: Person]{ //泛型下限 }
Int): MyRichInt = {
new MyRichInt(arg)
}
def main(args: Array[String]): Unit = {
// 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范
围内查找能调用对应功能的转换规则,这个调用过程是由编译器完成的,所以称之为隐
式转换。也称之为自动转换
println(2.myMax(6))
}
}

## 隐式参数普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时, 就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。(1)同一个作用域中,相同类型的隐式值只能有一个 (2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。 (3)隐式参数优先于默认参数```scalaobject TestImplicitParameter { implicit val str: String = "hello world!" def hello(implicit arg: String="good bey world!"): Unit = { println(arg) } def main(args: Array[String]): Unit = { hello }}

隐式类

隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶 级的。

object TestImplicitClass { implicit class MyRichInt(arg: Int) { def myMax(i: Int): Int = { if (arg < i) i else arg } def myMin(i: Int) = { if (arg < i) arg else i } } def main(args: Array[String]): Unit = { println(1.myMax(3)) }}

implicit var a = 1 def myTest():Unit = { println("---"+ implicitly[Int]) }

泛型

class MyList[+T]{ //协变 }

class MyList[-T]{ //逆变 }

class MyList[T] //不变

说明 协变:Son 是 Father 的子类,则 MyList[Son] 也作为 MyList[Father]的“子类”。

逆变:Son 是 Father 的子类,则 MyList[Son]作为 MyList[Father]的“父类”。

不变:Son 是 Father 的子类,则 MyList[Father]与 MyList[Son]“无父子关系”。

泛型上下限

Class PersonList[T <: Person]{ //泛型上限 }

Class PersonList[T >: Person]{ //泛型下限 }

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。