赞
踩
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这门语言。
基于JDK1.8
下载scala2.12.11
配置scala环境变量
package chapter01 class 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() } }
编译后生成的class
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="\006\001}2Aa\003\007\001\037!Aa\003\001B\001B\003%q\003\003\005#\001\t\005\t\025!\003$\021\0251\003\001\"\001(\021\025a\003\001\"\001.\017\025\tD\002#\0013\r\025YA\002#\0014\021\0251c\001\"\0015\021\035)dA1A\005\002YBaa\016\004!\002\0239\002\"\002\035\007\t\003I$aB*uk\022,g\016\036\006\002\033\005I1\r[1qi\026\024\b'M\002\001'\t\001\001\003\005\002\022)5\t!CC\001\024\003\025\0318-\0317b\023\t)\"C\001\004B]f\024VMZ\001\005]\006lW\r\005\002\031?9\021\021$\b\t\0035Ii\021a\007\006\00399\ta\001\020:p_Rt\024B\001\020\023\003\031\001&/\0323fM&\021\001%\t\002\007'R\024\030N\\4\013\005y\021\022\001B5oM>\004\"!\005\023\n\005\025\022\"aA%oi\0061A(\0338jiz\"2\001\013\026,!\tI\003!D\001\r\021\02512\0011\001\030\021\025\0213\0011\001$\003%\001(/\0338u\023:4w\016F\001/!\t\tr&\003\0021%\t!QK\\5u\003\035\031F/\0363f]R\004\"!\013\004\024\005\031\001B#\001\032\002\rM\034\007n\\8m+\0059\022aB:dQ>|G\016I\001\005[\006Lg\016\006\002/u!)1H\003a\001y\005!\021M]4t!\r\tRhF\005\003}I\021Q!\021:sCf\004") 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) { } }
var 变量名 :变量类型 = 值
val 常量名 :常量类型 = 值
变量类型都可省略,编译器会自动推断
能使用常量的地方不用变量
(1) 声明变量时,类型可以省略
(2) 类型确定后不可以修改
(3) 变量声明时,必须有初始值
(4) 声明变量时,可以使用var和val,var可以变,val不可变
以操作符开头,且只包含操作符(+ - * / # !等)
用反引号....
包括的任意字符串,即使是 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
(1)字符串,通过+号连接 ,可以字符串乘法
(2)printf 用法:字符串,通过%传值。
(3)字符串模板(插值字符串):通过$获取变量值
var age="hello"
println(s"${age}")
var num = 2.3456
println(f"The num is ${num}%.2f")//保留两位小数
println(raw"The num is ${num}%.2f")//raw 输出原格式
//三引号格式 可以换行写多行文本,保持原格式
s"""""".stripMargin
StdIn 就是new Scanner
基本语法
StdIn.readLine()、StdIn.readShort()、StdIn.readDouble()
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()
}
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,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数
语法与java没有区别
但每个分支都可以返回值
返回的类型为分支代码块的最后一行内容
val age = StdIn.readInt()
var result = if (age>18){
println("18")
15
} else{
"000"
}
println(result)
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)
因为 while 中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免 的使用变量,而变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量 造成了影响,所以不推荐使用,而是推荐使用 for 循环。
与java语法相同
Scala 内置控制结构特地去掉了 break 和 continue,是为了更好的适应函数式编程,推 荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable 控制结构来实现 break 和 continue 功能。
import scala.util.control.Breaks
import 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("正常结束循环")
}
1)核心概念
(1)为完成某一功能的程序语句的集合,称为函数。
(2)类中的函数称之方法。
2)案例实操
(1)Scala 语言可以在任何的语法结构中声明任何的语法
(2)函数没有重载和重写的概念;方法可以进行重载和重写
(3)Scala 中函数可以嵌套定义
(1)可变参数
(2)如果参数列表中存在多个参数,那么可变参数一般放置在最后
(3)参数默认值,一般将有默认值的参数放置在参数列表的后面
(4)带名参数
可变类似于python
def hello (*str):
print(type(str))
hello("sac","1")
------------------------
<class 'tuple'>
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="张三")
函数至简原则:能省则省
(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
(2)如果函数体只有一行代码,可以省略花括号
(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
(4)如果有 return,则不能省略返回值类型,必须指定
(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
(6)Scala 如果期望是无返回值类型,可以省略等号
(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
匿名函数 lambda表达式
没有名字的函数就是匿名函数。
(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)
函数对象
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
}
闭包:函数式编程的标配
闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包
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将局部变量创建了函数对象打成了包放在了堆内存里,
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)
}
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... 10 f... 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
}
}
当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。
Scala 有两种包的管理风格,一种方式和 Java 的包管理风格相同,每个源文件一个包(包 名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系,如 com.atguigu.scala。另一种风格,通过嵌套的风格表示层级关系,如下
package com{
package atguigu{
package scala{
}
}
}
第二种风格有以下特点:
(1)一个源文件中可以声明多个 package
(2)子包中的类可以直接访问父包中的内容,而无需导包
Scala 中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对 应包下所有 class 和 object 的共享变量,可以被直接访问。
package object com{
val shareValue="share"
def shareMethod()={}
}
如采用嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象 与包声明在同一作用域中。
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._
定义类
[修饰符] class 类{
}不加修饰符默认为public,加上public会报错
一个scala文件可以定义多个类
class student{
//该注解默认生成set get
@BeanProperty
private var:String name = "1"
//默认public 但底层都是private
//假如想要属性为空 name = _ 相当于null 或0
}
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[包名]增加包访问权限,包名下的其他类也可以使用
和 Java 一样,Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。
Scala 类的构造器包括:主构造器和辅助构造器
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
说明:
(1)辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分。
(2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
(3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
(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 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写
1)基本语法 object Person{ val country:String=“China” }
2)说明
(1)单例对象采用 object 关键字声明
(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
apply 方法
通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。
如果想让主构造器变成私有的,可以在()之前加上 private。
当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构 建对象时,调用的其实时伴生对象的 apply 方法。
5.9 特质(Trait)
就是java中的interface
with来实现
基本语法
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
(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) } }
枚举类:需要继承 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
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 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
定义
定义: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 方法创建数组对象
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长度的range a.indices
ArrayBuffer 是有序的集合,增加元素使用的是 append 方法(),支持可变参数
多维数组
val arr = Array.ofDim[Double](3,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
可变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)
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) //合并map map ++= mutable.Map ("2"-> "2") println(map)
//元组 最大只有22个元素 创建方式跟py一样 () 下标从一开始不可变
//并不是Any类型的列表 每个元组长度都有一个单独类 Tuple1-22
var 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))
}
通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最 终获取结果。
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)隐式参数优先于默认参数 ```scala 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]{ //泛型下限 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。