scala
(scalable的简写)
scala是一个比较冷门的语言,不太被人们所知道
为什么这么冷门的语言现在被我们使用
很多的大数据的项目的源码是是用scala语言编写的。
因为大数据技术不断被人们使用,所以scala也逐步被认知
scala是一个基于JVM,多范式的一种类似于java的编程语言
基于JVM:
运行在java平台之上,并且有自己的scala解释器。
多范式:
范式:代表着一种规范
c语言: 面向过程的编程范式
java语言: 面向对象的编程范式
scala语言: 面向对象的编程范式、函数式编程范式、交互式编程范式
环境的搭建
步骤:
1.安装 xxx.msi 下一步。。。
2.添加环境变量
3.验证 cmd> scala
开发工具的安装
a.eclipse
1.下载相应版本的插件压缩包
2.解压缩插件
3.把features和plugins的内容全部复制到eclipse的安装目录的相应目录下
4.打开eclipse正常创建项目,包,类
b.idea
1.安装插件
File->settings->plugins->安装插件->搜索scala->点右侧的安装按钮
i.在线安装
如果一切顺利,安装完毕重启idea就可以使用了
ii.如果在线安装有问题,可以下载插件,离线安装
根据错误提示的地址,根据scala插件版本
下载插件的jar包,注意千万不要解压缩
点击 install plugins from disk 选项
选择刚才下载的jar包
2.使用
1.创建普通maven工程,在项目名右键添加框架支持,选择scala
2.在src下创建package和object
3.写代码
四个名词
1.字面量:等号右侧能直观看见的内容
2.变量(var):可以变化的量
3.值(val):不可变化的量
4.类型:数据类型
变量:可以变化的量
语法:
var 变量名[:数据类型] = 字面量
变量名 = 另一个字面量
注意:
如果使用类型推导,第一次推导出来的类型就是它的类型
即使对当前变量做修改,类型按照第一次确定的类型执行
值:不可以发生变化的量
语法:
val 变量名[:数据类型] = 字面量
注意:
用法与var完全一致,唯一不同是不可以修改值的内容
类型推导:
前提:定义变量或值时,没有指定数据类型
通过字面量的类型自动推断出当前变量的类型的过程
适用于类型可读性强的情况下使用。
数据类型
正常也可以按照java的标准分类:分为基本数据类型和引用数据类型
数值类型:
Byte
Short
Int
Long
Float
Double
类型转换:
a.低转高(直接转换):
val i:Int = 123
val l:Long = i
b.高转低(强制转换):
数据表示范围不同,可能会丢失数据,所以必须进行强制转换,方法toType
val l:Long = 123L
val i:Int = l.toInt
非数值类型
Char:字符,用单引号表示,与Int类型随意转换,没有高低之分
Boolean:true false
String:字符串 对应的类是java.lang.String
既能满足java的String用法,也有Scala自己的用法
a.字符串的运算
+ :字符串拼接
* :字符串复制 java不支持,scala支持
b.完全原样输出(""" 内容""") 包括转义字符
val s =""" hello world"""
c.字符串内插
在字符串内可以引用变量,可以进行计算,可以写代码
语法:
val res = s"${...}" val f1 = f"${"hello"}%.3s"val f2 = f"${3.141592653}%.3f"
元组(Tuple):
盛放数据的容器,可以存放无限多个任意类型的数据。
用小括号表示一个元组,元组内的元素用逗号连接
表现形式:val tup = (元素,元素,…)
类型:
a.对于元组整体,类型是TupleN
(通过getClass获得,N为元组中元素的个数)
b.对于具体使用的时候,类型是与元组中的元素一一对应的类型
取元组中的某一个元素:tuple._n 取第n个元素
如果元组有嵌套元组,可以使用tuple._n._n的形式获取
两个元素的元组:
a.正常来说完全可以当做普通的元组
b.(key,value)完全等价于 key -> value 就是一个键值对形式
注意:-> 表现形式只代表键值对
()既可以表示元组也可以表示键值对
表达式和表达式块
表达式:100 1+1 “hello”+" world" "hello " * 5 …
有返回值的代码单元
表达式块:
如果一个语句无法完成表达式的话,可以使用表达式块{}完成
一个语句也可以使用表达式块,一个语句属于特殊的多个语句
表达式块内部的多个语句之间使用分号连接或者换行显示
表达式块内只返回最后一句话,
如果是语句,没有返回值,则整体的返回值为 ()
如果是表达式,有返回值,则整体返回值为最后一个表达式
语法:val a = {val b=20;b*5}
语句
val a=10 println(“aaa”) 没有返回值的表达式
控制语句分为判断和循环
判断语句:
a.if…else…
val res = if(条件判断式){执行语句或表达式}else if(条件判断式){执行语句或表达式}。。。else{执行语句或表达式}
b.匹配表达式 match…case…
1.基本使用
val res = 被匹配项 match{case xxx => {执行语句或表达式}case xxx => {执行语句或表达式}...} 注意:a.case匹配的一定是具体的值b.case匹配的值的类型一定与被匹配项保持一致
2.值绑定
val res = 被匹配项 match{case xxx => {执行语句或表达式}...case 值的名字 => {执行语句或表达式}}注意:a.可以使用变量名表示默认情况b.值绑定可以匹配所有的值c.模式匹配是按照顺序依次匹配d.值绑定应该放在所有匹配项的最下面
3.使用通配符代替值绑定
默认匹配情况可以使用_代替值的名字,比较简单
但是如果在默认匹配项中需要输出这个内容时,不太适合使用通配符
4.模式替换式
如果很多个匹配项执行的代码一样,
为了避免代码冗余,可以以|进行连接
case xxx | xxx | ... =>{ 执行的语句或表达式}
5.哨卫模式
在匹配某一项内容的时候,可以添加过滤条件
case ... if ... =>{执行的语句或表达式}
循环语句
for:已知次数的循环
1.语法:
for(临时变量 <- 可迭代对象){
循环体
}
2.生成数字的可迭代对象的方式
a. x to y (reverse)
没有前闭后开的限制,如果想要反转,直接加reverse
b. Range(x,y,s)
遵循前闭后开原则,可以加步长;
如果想反转,x和y互换,并且调整数据,把步长改为负数。
yield关键字:
可以把循环的每一个值最终汇总成一个集合的形式整体返回
val res = for() yield{
返回值
}
3.哨卫模式
在循环的过程中,过滤掉一些数据。
for(临时变量 <- 可迭代对象 if(条件判断式)){
循环体
}
注意:
判断条件返回值为true,当前值留下
判断条件返回值为false,当前值被过滤掉
4.嵌套循环 支持java的写法
简便方法:
for(临时变量1<- 可迭代对象 ; 临时变量2 <- 可迭代对象 ; …){
循环体
}
注意:
a.可以多层嵌套
b.临时变量的顺序代表嵌套的顺序
c.如果嵌套的层次比较多,可以把for的()替换成{}
while:已知条件的循环,先判断后循环
do…while:先执行后判断 与java用法一模一样
函数:
java中的方法
定义函数:
def 函数名(传参):返回值类型 = {
函数体
}
注意:函数体内返回值不加return关键字,最后一个表达式直接作为返回值
调用函数: 函数名()
无参函数:
1.定义无参函数时,函数名后面可以有括号或没有括号。
2.如果有空括号,调用的时候可加括号可不加括号;
如果没有括号,调用的时候一定不能加括号。有参函数:注意:参数必须有类型
1.普通参数
与java一样,传参的顺序一定要与定义函数时候的顺序保持一致
2.有默认值的参数
在定义参数的时候给定默认值,调用的时候不给这个参数传参,用默认值
在参数后面加 =xxx ,有默认值的参数的个数不限,尽量把有默认值的参数放在最后
3.指定参数传参
参数名和具体的值(默认值或调用时候传的值)相当于是键值对。
可以以 参数名=xxx 的形式进行传参
不管是否为默认值参数,按顺序传参,可以单独指定某个参数
不按顺序传参,必须所有的参数都以指定参数形式传参
4.不定长参数
可以传递0到无限个参数的形式
在参数的后面加* 这个参数是一个可迭代类型,可以直接循环
不定长参数要放在所有参数的最后面
5.参数组
每个参数都加一个括号,相当于是函数的链式调用
函数的几种用法
递归函数
函数自己调用自己本身。
尾递归
在递归函数的基础上,在内存上又做了一些优化
1.递归函数
2.函数的上面 @annotation.tailrec
3.最后一个语句一定是调用自己
嵌套函数
在函数的内部可以定义函数
注意:
a.内部函数只属于外部函数(作用域只能在外部函数内)
b.外部函数和内部函数的名字可以一样也可以不一样,建议不一样。
首类函数
函数不仅能正常的声明和调用,而且可当做数据类型用在scala任何地方。
函数如果加括号相当于是调用函数,获得的是函数的返回值;
如果想要函数的整体,只能用函数名来代替这个函数。
val func:函数类型 = 函数名
如果当前函数的所有参数没有固定值,可以简写为 val func = 函数名 _
函数的类型:
参数的类型 => 返回值的类型
注意:
a.参数如果两个及以上,必须加括号;一个参数可加可不加
b.函数的类型一定都是类型
高阶函数:
以函数作为参数或以函数作为返回值的函数。
在scala中包括spark是以函数作为参数为主
语法:
def 函数名(参数:类型,…函数参数:函数类型,…)
调用:
只要函数类型符合定义的函数类型,都可以传递
匿名函数:
只有参数和函数体,没有函数名的函数叫做匿名函数
可以直接用val进行接收,无需使用def定义
语法:
(参数名:参数类型) => {函数体}
某种情况下可以使用通配符对匿名函数做简化
可以使用通配符的条件:
1.函数体要按顺序使用参数
2.有一个及以上参数,且必须被使用
3.每个参数的使用次数只能为1次
不满足上述三个条件,只能使用普通的匿名函数
柯里化:
调用函数的时候,通常要在调用的时候指定每一个参数(有默认值的情况除外)。
在一个函数中,如果想固定参数里的某个参数,每次调用的时候只传其他参数
可以使用参数组的形式把函数理解为链式调用
把固定的参数都放在参数名的后面,把所有其他参数用 _
语法:val xxx = 函数名(固定值),… _
适用场景:
一般某个参数比较常用的时候,可以固定
避免每次使用都重复传递这个参数。
def factoror(x:Int,y:Int) = {
y%x==0
}
val fac = factoror _ fac(10,20)
val fac_x10 = factoror(10) _ fac(30)
val fac_x20 = factoror(20) _ fac(30)
…
传名函数和传值函数
以参数来确定为传值还是传名。
解析函数参数的时候两种方式
传值调用(call-by-value)
参数先计算出结果,把结果带入到函数体内使用
适合于在函数体内使用多次这个参数的时候使用传名调用(call-by-name)
参数的表达式整体带入到函数体内,用到参数时计算
适用于在函数体内有可能使用不到这个参数的时候使用。两种函数的表现形式
a.传值调用
正常传递 ()=>Unit
b.传名调用
参数有点不太一样 => Unit
集合:
List:一个不可变的单链表
创建方式:
1、直接创建
val xxx:List[泛型] = List[泛型](元素,元素,....)可以在List中存储任意多个任意类型的数据。val list = List(1,"",true,(1,2,3))泛型:对集合中数据类型的规范如果指定泛型,集合中的元素类型必须保持一致;如果集合中有很多个类型的数据,泛型应为Any
注意:
a.列表可以不写泛型,可以进行类型推导
b.列表中可以存在n个任意类型的元素,这种情况可以不指定泛型或泛型为Any
c.如果想规范元素的类型,可以指定具体List[泛型]
2、通过Nil创建列表
val list = 1 :: 2 :: 3 :: Nil
两个常用的方法:
head():获取list里的第一个元素(具体的值)
tail():获取list里除了第一个元素之外,剩下元素组成的集合(是一个集合)
获取列表中的第n个元素:
使用小括号,直接加索引位置获取 语法: list(index)
例:val element = list(index)
遍历列表的几种方式:
a.普通for循环
b.变成迭代器形式,通过while(xxx.hasNext){xxx.next}
c.while(null!=xxx && xxx.length/size>0)
d.while(xxx.nonEmpty)
e.while(!xxx.isEmpty)
f.while(xxx!=Nil)
g.递归遍历方式
h.高阶函数foreach(println)
object CollectionTest {def createList() = {var itemList:List[Any] = List[Any](3,"hello",true,("a"),3.14,List("lhs"))// println(itemList.head)// println(itemList.tail)//第一种遍历方式// for(item <- itemList){//println(item)// }//第二种遍历方式// val itemIter = itemList.iterator// while(itemIter.hasNext){//println(itemIter.next())// }//第三种遍历方式// while(null!=itemList && itemList.length>0){//println(itemList.head)//itemList = itemList.tail// }//第四种遍历方式// while(itemList.nonEmpty){//println(itemList.head)//itemList = itemList.tail// }//第五种遍历方式// while(!itemList.isEmpty){//println(itemList.head)//itemList = itemList.tail// }//第六种遍历方式// while(itemList!=Nil){//println(itemList.head)//itemList = itemList.tail// }//第七种遍历方式itemList.foreach(println)}def main(args: Array[String]): Unit = {createList()}}
关于list的常用高阶函数
map和flatMap的区别?面试可能会问的问题
map():
对list里的每个元素做一些操作,与foreach有点像,
但是foreach没有返回值,而map有返回值。
特点:
1.map之前是列表,map之后还是列表
2.map之前有多少元素,map之后还有多少元素
3.变化的是每个元素的内容
变化规则由作为map参数的函数决定flatMap():
对list里的每个元素做一些操作,但是显示的结果只有一个集合。
flatMap = map + flatten
先做map,然后在做flatten操作,把列表中的所有集合的元素都以一个List形式展示
list常用的一些函数
列表的常用方法
1.:: Cons操作符,向列表中追加元素
语法:
//向左添加
a… :: 元素 :: 元素 :: 列表
//向左添加
b.列表.::(元素).::(元素)…
//向右添加
c.列表.:+(元素).:+(元素)…
注意:
a.如果列表为Nil的话,代表的是创建列表
b.正常是向列表的左侧添加元素
c.添加的内容不管是什么,都以元素的形式添加
2.::: 向列表中添加列表里的所有元素
已有list ::: 新list
以一个列表的形式展示两个列表中的所有元素
只能添加List,不能添加Set和Map
3.++ 向列表中添加List,Set或Map的所有元素
可以向列表中添加任何集合的内容,不是必须为List
4.==
判断两个列表里的内容是否相等
5.take / takeRight
take:获取列表里的前n个元素
takeRight:获取列表里的后n个元素
6.drop / dropRight
drop:删除列表里的前n个元素,但是不改变原列表
dropRight:删除列表里的后n个元素,也是不改变原列表
7.flatten
扁平化,将一个列表里所有列表的元素拿出来放在最外层列表当中
8.partition
按条件拆分,把一个列表按照某个条件分成两个列表
9.splitAt
按数量拆分,把一个列表按照某个条件分成两个列表
10.slice
获取两个索引之间的元素,前闭后开
11.排序
a.sorted
按照自然顺序排序
b.sortBy
按照某个条件进行排序,比如按照字符串长度排序、
c.sortWith
可以规定排序的顺序
12.distinct
对列表中的元素去重
13.filter
过滤器,过滤掉列表中的某些值。参数的返回值为boolean类型,为true留下
14.拉链操作
zip:两个列表的每个元素一一对应,形成两个元素的元组。
最终还是列表的形式,如果长度不统一,以最短的列表为主进行匹配。
zipWithIndex:把列表里的每个元素与它的索引位置拉链成一个键值对的形式。
规约列表:
把列表收缩为单个值,称为规约列表
数学类型的规约
1.max 获得列表中的最大值
2.min 获得列表中的最小值
3.product 获得列表中的所有元素的乘积
4.sum 获得列表中所有元素的和
布尔类型的规约
1.contains(元素)
判断是否包含具体元素,有一个符合返回true
2.exists(xxx=>Boolean)
按条件判断元素,有一个符合返回true
3.forAll(xxx=>Boolean)
按条件判断元素,所有元素全都符合返回true
4.startsWith(元素)
以某个元素开头,返回true
5.endsWith(元素)
以某个元素结尾,返回true
通用的列表规约操作
1.reduce(_-_) 对列表里的所有元素规约reduceLeft(_-_)同reducereduceRight(_-_)规约的规则一样,顺序从右向左2.fold(10)(_-_) 在reduce的基础上有一个默认值foldLeft(10)(_-_)同foldfoldRight(10)(_-_)规约的规则一样,顺序从右向左3.scan(10)(_-_) 计算过程与fold一样,但是以List显示所有结果scanLeft(10)(_-_)同scanscanRight(10)(_-_)计算规则一样,顺序从右向左
集合类型的转换
1.toString
把一个列表的整体完全变成字符串形式
2.mkString
一个参数:使用这个参数把所有的元素连接在一起
三个参数:在一个参数基础上,添加整体的开始和结束符号
3.toList
把集合转换为List类型
把可变的列表转成不可变的列表
4.toSet
把集合转换为Set类型
把可变的集合转成不可变的集合
5.toMap
把集合转换为Map类型
把可变的Map转成不可变的Map
6.toBuffer
不管什么类型的集合,都可以通过此方法转成可变类型集合
Java和Scala之间的集合的兼容性
由于java和scala集合里的子类太多,不建议使用这种方式。
import scala.collection.JavaConverters._
asJava asScala
Set:
无序,不重复的集合,用法与List一样
Map:键值对的集合
Map里的元素可以 (key,value) 或 key -> value 形式表示
语法:
a.Map((key,value),(key,value),…)
b.Map(key -> value,key -> value,…)
获取某个key的value值
a.map(key) 获得具体的值
b.map.get(key) 获得一元集合类型的值
什么是可变?什么是不可变?
可变:本身发生变化的,不会在内存中新开辟空间
不通过重新赋值的形式就改变原来内容的
不可变:本身没有发生变化,在内容中新开辟空间
通过重新赋值的形式修改原来内容
可变集合:
不重新开辟内存空间,在原内存地址上直接修改
在scala.collection.mutable包下
使用可变集合的话,一定要指定包使用
不可变集合:
重新开辟内存空间,改变地址
在scala.collection.immutable包下
immutable包相当于java中的lang包,自动导包
简单来记:
不可变集合需要重新赋值,可变集合不需要。
Array:
长度不能发生变化,元素内容可以变化的一个容器
创建数组
语法:Array[泛型](元素)new Array[泛型](n)//val colors = Array[String]("red","yellow","blue")val colors = new Array[String](3)colors(0) = "red"colors(1) = "yellow"colors(2) = "blue"colors(3) = "white"//错误的,数组越界
注意:
a.两种方法都可以创建不可变数组
b.这里所谓的不可变数组表示长度不可变
c.如果创建一个有长度的空数组,按照泛型显示初始值
ArrayBuffer:
是一个可变的索引集合,相当于一个动态的数组
长度和元素内容都可以发生变化的一个容器
创建ArrayBuffer
语法:ArrayBuffer[泛型](元素)new ArrayBuffer[泛型](n)1.val colors = ArrayBuffer[String]("red","yellow","blue")2.val colors = new ArrayBuffer[String](n)colors.append("red")colors.append("yellow")colors.append("blue")colors.append("black")colors.append("white")
注意:
a.ArrayBuffer 初次赋值应该以append的形式追加元素
之后修改值时可以使用索引的形式
b.append元素数量不受创建的限制,可以动态增加
c.使用的时候必须指定scala.collection.mutable包
可变集合创建:
通过不可变集合转换成可变集合
List,Set,Map都可以使用toBuffer转成可变类型
转成的都是 ArrayBuffer 这个可变类型
ArrayBuffer可以通过toType转成不可变类型
直接指定mutable包下的集合使用
方式比较直接,直接引包或指定包就可以使用
类型就是自己相应的可变数据类型
不可变类型 可变类型子类ListBufferListBufferSetSet HashSetMapMap HashMap
集合.newBuilder[泛型]
添加元素: .+=
获取最终集合: .result
一元集合
没有元素或只有一个元素的集合。
Option:值的存在或不存在,可以当做数据类型用在任何地方
Some:是Option的子类,代表值的存在 Some(xxx)
None:是Option的子类,代表值不存在 None
对Option类型的结果处理函数
1.fold()()
第一个参数为返回值为None的时候显示的内容
第二个参数为返回值为Some的时候执行函数(必须有返回值)
2.getOrElse()
第一个参数为返回值为None的时候显示的内容
如果返回值为Some的话,默认原样输出
3.orElse()
与getOrElse一样,只不过参数为Option类型,结果也是Option类型
一般使用Some类型,表示的是不管是否有值都用Some表示。
4.匹配表达式
case Some(x) => x
case None => -1
Try:代码执行的成功或失败,可以当做数据类型用在任何地方
success:是Try的子类,代表代码执行成功
以正确执行代码的最后的返回值作为这个集合的元素
failure:是Try的子类,代表代码执行报异常
以报错信息作为这个集合的元素
对Try类型的处理函数
1.foreach
原样输出一元集合里的内容(只适用于Success)
2.getOrElse
给定失败的默认值,成功原样输出
3.orElse
用法与2一致,值为Try类型
4.toOption
Success转成Some,Failure转成None
5.模式匹配
面向对象:
类:具有相同属性和方法的一组对象的集合
对象:类的一个具体的实现
定义类:
class 类名{
属性(val或var)
方法(函数)
}
调用类:
val 实例化对象 = new 类名
实例化对象.属性
实例化对象.方法
类参数:
在scala当中,可以在定义类的时候定义参数,方式与函数相同。
但是在new这个类的时候,必须传参。
类属性:
在类参数的前面添加val或var,这个类参数就变成了类属性。
构造器:
主构造器:
类本身就是主构造器
类中除了属性和方法以外,可以执行的语句都属于构造器的初始化执行。辅助构造器:
在类中可以以this关键词为函数名定义的构造函数
语法:def this(参数) = {}
可以进行重载,但是注意顺序
每个辅助构造器需要调用其他辅助构造器或主构造器。
调用其他构造器的代码必须放在第一行
辅助构造器的参数可以随意传,但是要按照要求使用。
scala中引入包的几种方式
1.在类的最上面引入,对全局有效import <package>.<class>2.在使用这个类的代码位置添加,只对当前代码有效在代码里直接写 <package>.<class>3.可以引入一个包下的多个类import <package>.{<class1,class2>,...}4.可以给类起别名,很多包都有这个名字的类或者类型比较复杂时候使用import <package>.{<class> => 别名,<class> => 别名,...}5.引入当前包下所有的类import <package>._
懒值
类中使用的属性都是在类的第一次实例化的时候创建的。
但是,懒值则在使用这个属性的时候才创建。
val x = {
println(“creating x”)
10
}
lazy y = {
prinltn(“creating y”)
20
}
继承
1.一个类可以使用extends关键字扩展最多一个其他类。
2.可以使用override关键字覆盖所继承的方法。
3.类中的字段和方法可以使用this关键字访问。
4.父类中的字段和方法可以使用super关键字访问。
重载
在一个类中,函数名相同,参数不同的
什么是参数不同?
1.参数个数不同
2.参数类型不同
3.参数顺序不同
抽象类
一个类中至少存在一个方法或属性只声明而没有具体定义,这个方法就是抽象方法,当前类就是抽象类。
使用abstract关键字修饰class,抽象的属性或方法不需要abstract修饰。
抽象类不能使用new创建实例,只能通过子类继承。
抽象类里的抽象属性或方法,在子类中必须重写。
内部类:
scala内部类是属于外部类的实例化对象的
创建内部类
new 外部类实例化对象.内部类名
在外部类或内部类里面加
别名=>
可以使用别名代替正常的类名
访问修饰符:
公共成员(public)
如果没有指定任何修饰符,就是public。
可以在任何地方使用
保护成员(protected)
只允许在定义了该成员的类的子类中被访问
私有成员(private)
仅在当前类中使用。
apply
相当于类的实例化对象的初始化方法,相当于一个快捷方式。
可以把类的实例化对象当做函数使用。
对象(object)
是一个类的类型
特点:
a.只能存在不超过1个实例 -> 单例模式
b.不能使用new关键字创建实例
c.只需要按名直接访问属性和方法
相当于java中的静态类
伴生:
在一个文件当中,类和对象的名字相同,这个类和对象互为伴生。
类是对象的伴生类
对象是类的伴生对象
先有类,后有对象;
对象里的apply方法,默认创建它的伴生类的实例化对象,
apply方法的参数与伴生类的类参数或类属性保持一致。
好处:
private在伴生类和伴生对象里的话,可以互相访问的。
case类(样例类):
在用case修饰的类当中默认存在一些方法
a.apply object
b.unapply object
c.equals class
d.hashCode class
e.toString class
f.copy class
Trait
是一种支持多重继承的类。
相当于是java里的接口。
使用with实现接口。
在有extends和多个with的时候,当前类的最右侧的类为直接父类,
向左辈分依次增高。
写文件:
从控制台读取数据
StdIn.readLine() //读取字符串类型的数据
StdIn.read… //读取各种类型的数据
写文件
与java保持一致就ok
读文件:
val file = Source.fromFile(“path”)
val list = file.getLines().toList
list.foreach(println)
file.close()
jdbc:
方式与java一模一样
但是语法要使用scala自己的语法
scala写jdbc没有强制要求捕获异常
两种捕获异常的方式
a.try…catch…
b.util.Try().getOrElse
隐式转换
以一种隐蔽的方式把某些不符合常规的内容或类型转换成需要的内容或类型
过程:
首先发现某些不符合常规的地方,然后去所有能找的范围(包括当前类和import引入的内容)里找所有的implicit修饰的方法或属性,如果找到可以适用的,自动调用,不需要人为操作。与函数名和参数名无关,只与转换内容有关。
分类:
a.关于函数的隐式转换
找能做某些转换的implicit函数,只有存在,自动调用
b.关于参数的隐式转换
找符合implicit参数的内容,只要存在,自动传参
说明:
尽量把所有的关于隐式转换的内容都放在一个class或object中,使用的时候通过import引入就ok。