Spark、Kafka等相关大数据技术框架底层都是由Scala编程语言编写的,Spark我们自己编写分布式程序时,Spark提供了多种编程语言风格,但是我们比较常用的是使用Scala编程。
Step1:安装并检测到JDK1.8版本或者其以上版本。
Step2:进入Scala的官网,点击自己想要的版本进行下载,我下载的是2.13.11,然后点击Windows对应的后缀为.msi的版本进行下载。
Step3:下载到本地后,双击 scala-2.13.11.msi
进行安装
因为scala占的内存不是很大,并且后续也不会自动变大所需要的存储空间,所以我就放在C盘不改变盘符了。
Step4:即可安装成功!打开命令行窗口输入命令scala -version
进行查看是否安装成功!
Step1:我的电脑->右键->属性->高级系统设置->环境变量
Step2:用户变量栏目下新建->变量名为:SCALA_HOME,变量值为中scala安装的电脑路径
Step3:配置path变量->双击用户变量下的Path,进行如图所示的配置
Step4:一定要将所有的确定都点击完成后再关闭窗口。
打开电脑的命令行窗口,使用Scala的REPL(Read Eval Print Loop,交互式解释器)进行环境的搭建的基本测试。
前三个命令为:Scala的定义常量与变量的语法,后续会说到;
第四个命令为:将常量重新赋值时报错的场景;
第五个命令为:将数据类型为Int的变量b,重新赋值为数据类型为字符串的zs时报错的场景。
针对第五个命令报错的进一步说明:
在电脑某文件夹下新建一个HW.scala文件,并进行内容的编写。然后我们使用命令行窗口进行编译和运行。
class HW{
}
object HW{
def main(args:Array[String]):Unit={
println("HW")
}
}
编译之后会生成两个新的文件
Step1:首先下载idea中提供的Scala的插件,安装并重启。
Step2:新建一个maven项目。
Step3:项目单机右键,选择Add Framework Support,将Scala的复选框勾选上,然后点击CREATE,再点击brower…选择Scala的安装路径。
Step4:新建一个名为scala的文件夹用于存放scala编写的代码,并将此文件夹设置为Sources Root
Step5:编写scala代码
我们在刚刚下载Scala的官网下载对应的源码包scala-sources-2.13.11.tar.gz
,然后将压缩包进行解压到本地的稳定目录下。
Scala完全面向对象,故Scala去掉了Java中非面向对象的元素, 如static关键字, void类型
Scala无static关键字, 由object实现类似静态方法的功能(类名 .方法名);class关键字和Java中的class关键字作用相同,用来定义一个类。
class就是Scala中类,类中不能声明静态内容,所有的静态内容必须声明在该类的Object伴生对象中
对于无返回值的函数,Scala定义其返回值类型为Unit类。
Scala 注释使用和 Java 完全一样。
单行注释://
多行注释:/* */
文档注释:/** */
常量:在程序执行的过程中,其值不会被改变的变量 。
Java 与Scala变量和常量语法对比
Java
Scala
var 变量名 [: 变量类型] = 初始值
val 常量名 [: 常量类型] = 初始值
Scala声明变量的特点
声明变量时,类型可以省略,编译器自动推导,即类型推导。
类型确定后,就不能修改,说明 Scala 是强数据类型语言。
变量声明时,必须要有初始值 。
在声明/定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改。
var 修饰的对象引用可以改变,val 修饰的对象则不可改变,但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)。
代码示例
class Demo01{
}
object Demo01 {
def main(args: Array[String]): Unit = {
//声明变量
var a = 1
var b:Int = 1
a = 2
b = 2
println(a)
println(b)
//声明常量
val c = 1
//people1是var修饰的,people1的属性可以变,而且people1本身也可以变
var people1 = new People()
people1.name = "ls"
people1 = null
//people2是val修饰的,那么people2本身就不可变(即people2的内存地址不能变),但是people2的属性是可以变,因为属性并没有用val修饰。
val people2 = new People()
people2.name = "zs"
people2 = null // 错误的,因为p2是val修饰的
}
}
Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可以起名字的地方都叫标识符。
命名规则——Scala 中的标识符声明,基本和 Java 是一致的,但是细节上会有所变化,有以下三种规则
Scala标识符由字母、数字、下划线、数学符号、$美元符号组成,其中数字不能开头。
如果标识符是数学符号,那么标识符中只能包含数学符号。
Scala的标识符可以是关键字和保留字,但是得使用*``*把关键字和保留字包起来即可。
Scala39个关键字:
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
代码示例
object Demo02 {
def main(args: Array[String]): Unit = {
var a1 = 1
var +-* = 2
println(+-*)
var `var` = 3
println(`var`)
}
}
Scala的输出语言
使用Java的输出语句:System.out.xxxx
普通的输出语法:print println
模板输出语法:print/println(s"我有一个账号:$account")
格式输出语法:printf(可以使用一些特殊字符当作占位符,然后在方法后面传递参数取代占位符)
%d 十进制数字
%s 字符串
%c 字符
%e 指数浮点数
%f 浮点数
%i 整数(十进制)
%o 八进制
%u 无符号十进制
%x 十六进制
%% 打印%
代码示例:
object Demo03 {
def main(args: Array[String]): Unit = {
print("zs")
println("ls")
var count = "123456"
println(s"我有一个账号:$count")
printf("我有一个账号%s",count)
}
}
在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。
直接无缝衔接使用Java的键盘输入 —— Scanner
使用Scala提供的自带的键盘输入 —— StdIn.readxxx()
基本语法
StdIn.readLine()
StdIn.readShort()
StdIn.readDouble()
代码示例
import scala.io.StdIn
object Demo04 {
def main(args: Array[String]): Unit = {
//字符串
println("输入姓名:")
var name = StdIn.readLine()
//整形数字
println("输入年龄:")
var age = StdIn.readInt()
//浮点型数字
println("输入薪水:")
var salary = StdIn.readDouble()
//输出
println(s"name = $name" )
println(s"age = $age" )
println(s"salary = $salary")
}
}
Java:基本数据类型:四类八种、引用数据类型。
Scala:没有基本数据类型一说,所有的类型都是对象,所有类型的顶尖父类是Any。
Any
AnyVal (数值类型)
AnyRef(引用类型):Java中的所有类、Scala中所有类、Scala中所有集合、Null
Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)。
Scala中的StringOps是对Java中的String增强。
Unit:对应Java中的void ,用于方法返回值的位置,表示方法没有返回值。Unit是一个数据类型,只有一个对象就是() 。Void不是数据类型,只是一个关键字。
Null是一个类型,只有一个对象就是null 。它是所有引用类型(AnyRef)的子类,不能给值类型赋值为Null。
Nothing :是所有数据类型的子类,主要用在一个函数没有明确返回值时使用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数。
代码示例
Scala 的整数类型就是用于存放整数值的,比如1,2,20等等。
数据类型 | 描述 |
---|---|
Byte [1] | 8 位有符号补码整数。数值区间为 -128 到 127 |
Short [2] | 16 位有符号补码整数。数值区间为 -32768 到 32767 |
Int [4] | 32 位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long[8] | 64 位有符号补码整数。数值区间为 -2^63 到2^(64-1)-1 |
整数型特点:
Scala 各整数类型有固定的表示范围和字段长度,不受具体操作的影响,以保证Scala 程序的可移植性。
Scala 的整型,默认为 Int 型,声明 Long 型,须后加‘l’或‘L’。
Scala 程序中变量常声明为 Int 型,除非不足以表示大数,才使用 Long。
Scala 的浮点类型可以表示一个小数,比如1.0,20.2f等等。
数据类型 | 描述 |
---|---|
Float [4] | 32 位, IEEE 754 标准的单精度浮点数 |
Double [8] | 64 位 IEEE 754 标准的双精度浮点数 |
字符类型可以表示单个字符,字符类型是 Char。字符常量是用单引号 ’ ’ 括起来的单个字符。
字符类型中的一些特殊字符
\t :一个制表位
\n :换行符
\ \ :表示\
\ " :表示"
布尔类型也叫 Boolean 类型,Booolean 类型数据只允许取值 true 和 false,boolean 类型占 1 个字节。
数据类型 | 描述 |
---|---|
Unit | 表示无值,和其他语言中 void 等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null , Null 类型只有一个实例值null |
Nothing | Nothing类型在Scala的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
当 Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:
1、自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
2、把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
3、(byte,short)和 char 之间不会相互自动转换。
4、byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。
注意:Scala 还提供了非常强大的隐式转换机制(隐式函数,隐式类等)
自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
1、将数据由高精度转换为低精度,就需要使用到强制转换
2、强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
在程序开发中,我们经常需要将基本数值类型转成 String 类型。或者将 String 类型转成基本数值类型。
1、基本类型转 String 类型(语法:将基本类型的值+“” 即可)
2、String 类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、 s1.toLong、s1.toShort)
3、注意事项在将 String 类型转成基本数值类型时,要确保 String 类型能够转成有效的数据,比如我们可以把"123",转成一个整数,但是不能把"hello"转成一个整数。
代码示例
var a = "zs" + (1+1)
Scala 运算符的使用和 Java 运算符的使用基本相同,只有个别细节上不同。
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | b=4; -b | -4 |
+ | 加 | 5+5 | 10 |
- | 减 | 6-4 | 2 |
* | 乘 | 3*4 | 12 |
/ | 除 | 5/5 | 1 |
% | 取模(取余) | 7%5 | 2 |
+ | 字符串相加 | “He”+”llo” | “Hello” |
对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。
对一个数取模 a%b,和 Java 的取模规则一样。
运算符 | 运算 | 范例 | 结果 |
---|---|---|---|
== | 相等于 | 4==3 | false |
!= | 不等于 | 4!=3 | true |
< | 小于 | 4<3 | false |
> | 大于 | 4>3 | true |
<= | 小于等于 | 4<=3 | false |
>= | 大于等于 | 4>=3 | true |
Java 和 Scala 中关于==的区别
Java:
==比较两个变量本身的值,即两个对象在内存中的首地址;
equals 比较字符串中所包含的内容是否相同。
Scala:
基本语法用于连接多个条件(一般来讲就是关系表达式),最终的结果也是一个 Boolean 值。
运算符 | 描述 | 实例 A=true B=false |
---|---|---|
&& | 逻辑与 | (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 |
【注意】Scala 中没有++、–操作符,可以通过+=、-=来实现同样的效果;
运算符 | 描述 |
---|---|
& | 按位与运算符 |
| | 按位或运算符 |
^ | 按位异或运算符 |
~ | 按位取反运算符 |
<< | 左移动运算符 |
>> | 右移动运算符 |
>>> | 无符号右移 |
Scala运算符本质上是一个函数,函数的名字是数学符号
当调用对象的方法时,点可以省略
如果函数参数只有一个,或者没有参数,()可以省略
代码示例:
object Demo06 {
def k():Unit={
}
def main(args: Array[String]): Unit = {
val s = new String("zs")
val s1 = "zs";
println(s ==s1)
println(s.eq(s1))
var c: Int = 1
c.+=(1)
c = c+1
println(c)
//c++
val people = new People()
people setName "zs"
var result = k
println(result)
}
}
Scala中元组类型 —— Scala中一种比较特殊的数据类型,Scala类
元组也是一种集合,集合有个特点:最多可以存放22个元素
代码示例:
object Demo07 {
def main(args: Array[String]): Unit = {
val a:Tuple1[String] = new Tuple1[String]("zs")
val b:Tuple2[String,Int] = new Tuple2[String,Int]("zs",2)
}
}
Scala中流程控制:控制代码的执行逻辑的
顺序流程:代码从上而下依次执行
分支流程:根据判断的不同 走不同的分支路线
if:scala和Java的if分支是一样的
switch:Scala中没有提供switch语句,而是提供了一个功能更加强大的模式匹配来实现类似于switch的功能。
xxx match{
case 值或者表达式 => {分支}
case 值或者表达式 => {分支}
case _ =>{}
}
循环流程
让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支
if (条件表达式) { 执行代码块 }
说明:当条件表达式为 ture 时,就会执行{ }的代码。
双分支
if (条件表达式) { 执行代码块 1 } else { 执行代码块 2 }
多分支
if (条件表达式 1) { 执行代码块 1 }else if (条件表达式 2) { 执行代码块 2 } …… else { 执行代码块 n }
嵌套分支
在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层。 分支外面的分支结构称为外层分支。嵌套分支最好不要超过 3 层。
if(){ if(){ …. }else{ …. } }
在 Scala 中没有 Switch ,而是使用模式匹配来处理。
模式匹配
语法: x match{
case 值|x [模式守卫if] => case分支语句
case 值|x [模式守卫if] => case分支语句
case _ => case分支语句
}
【模式守卫】模式守卫可以做范围匹配,一般使用模式守卫时,case需要x
代码示例:
object Demo08 {
def main(args: Array[String]): Unit = {
var a:String = "spring"
a match {
case "spring" =>
println("春暖花开1")
println("春暖花开2")
case "summer" =>
println("夏日炎炎")
case "autumn" =>
println("秋高气爽")
case "winter" =>
println("银装素裹")
case _ =>
println("输入的单词不是季节")
}
var b = 80
b match {
case b if b>=0 && b<60 =>{
println("不及格")
}
case b if b>=60 && b<70 =>{
println("及格")
}
case b if b>=70 && b<80 =>{
println("中等")
}
case b if b>=80 && b<90 =>{
println("良")
}
case b if b>=90 && b<=100 =>{
println("优")
}
case _ =>
println("输入成绩有误!")
}
var c = "zsl"
c match {
case "zs" => println("匹配到了张三")
case "ls" => println("匹配到了李四")
case _ => println("啥也没匹配到")
}
}
}
Scala为for循环这一常见的控制结构提供了非常多的特性,这些 for循环的特性被称为for推导式或for表达式。
范围数据循环to
for(i <- start to end){ print(i + " ") }
i表示循环的变量
<-表示遍历右边的语法结构
to表示从start遍历到end 左闭右闭
范围数据循环Until
for(i <- start until end) { print(i + " ") }
增强的for循环 —— 遍历集合或者数组
for(elem <- 集合/数组的变量)
循环守卫
for(i <- start to end if i != num) { print(i + " ") }
for (i <- start to end){ if (i != num) { print(i + " ") } }
循环步长
for (i <- start to end by num) { println("i=" + i) }
嵌套循环
for(i <- start to end; j <- start to end) { println(" i =" + i + " j = " + j) }
for (i <- 1 to 3) { for (j <- 1 to 3) println("i ="+ i + " j=" + j) } }
引入变量
for(i <- 1 to 3; j = 4 - i) { println("i=" + i + " j=" + j) }
for推导式一行中有多个表达式时,所以要加;隔断逻辑
for推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号,当包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号,如下
for { i <- 1 to 3 j = 4 - i } { println("i=" + i + " j=" + j) }
循环返回值
val res = for(i <- 1 to 10) yield i println(res)
将遍历过程中处理的结果返回到一个新Vector集合中,使用 yield 关键字。
注意 :一般很少使用。
倒序打印
for(i <- 1 to 10 reverse){ println(i) }
代码示例
object Demo09 {
def main(args: Array[String]): Unit = {
/**
* until类型的for循环
*/
for(i <- 1 until 10){
println(i)
}
/**
* to类型的for循环
*/
for(i <- 1 to 10){
println(i)
}
/**
* 循环守卫 等同于判断条件,循环中,满足了某个条件之后才会执行循环体
*/
for(i <- 1 to 100 if i % 2 == 0){
println(i)
}
/**
* for循环的步长控制
* 如果循环守卫和循环步长同时出现 先写循环步长 再写循环守卫
*/
for(i <- 1 to 100 by 3 if i % 3 ==0){
println(i)
}
/**
* 嵌套循环
*/
for(i <- 1 until 10;j <- 1 to i){
print(s"$i * $j = " + (i*j) + " ");
if (i ==j){
println()
}
}
/**
* for循环的返回值 for循环不能有循环体的
* 将for循环的结果放到一个集合当中
*/
var a = for(i <- 1 to 10) yield i
println(a)
/**
* for 循环的值倒序输出
*/
import scala.language.postfixOps
for(i <- 1 to 10 reverse){
print(i + " ")
}
}
}
Scala中的while和do…while的使用和Java语言中用法相同
while循环
do while 循环控制
Scala内置控制结构特地去掉break和continue,是为了更好的适应函数式编程,推荐使用函数式的风格替代break和continue的功能而不是一个关键字。Scala中使用 breakable控制结构来实现break和 continue 功能。
将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for ,while ,do while 均可以作为外层循环和内层循环。
【建议一般使用两层,最多不要超过 3 层】
函数基本语法
def 函数名(参数列表):返回值类型={
函数体
}
Java中的方法的定义语法:
方法控制修饰符 [static|final|abstract] 返回值类型 方法名(参数列表) [thorws 异常]{
方法体;
}
函数和方法的区别
为完成某一功能的程序语句的集合,称为函数。
类中的函数称之方法。
Scala 语言可以在任何的语法结构中声明任何的语法。
函数没有重载和重写的概念;方法可以进行重载和重写。
Scala 中函数可以嵌套定义。
函数分类
class Demo10 {
/**
* 无参数 无返回值的函数
*/
def a():Unit={}
/**
* 无参数 有返回值的函数
*/
def b():Int={
return 1;
}
/**
* 有参数 有返回值的函数
*/
def c(a:Int): Int = {
return a;
}
/**
* 有参数 无返回值的函数
*/
def d(a: Int): Unit = {
}
/**
* 多参数 无返回值的函数
*/
def e(a: Int,b:Int): Unit = {
}
/**
* 多参数 有返回值的函数
*/
def f(a: Int, b: Int): Int = {
return a+b;
}
}
可变长参数
参数默认值,一般将有默认值的参数放置在参数列表的后面
带名参数
import java.io.IOException
/**
* 函数的第一个问题: 函数名:小驼峰
* 函数的第二个问题: 函数的参数问题
* 1、参数列表的声明语法: 参数名:参数类型,参数名:参数类型
* 2、可变长形参:参数名:数据类型* 必须位于参数列表的最后一个位置,而且一个方法只能有一个可变长形参
* 3、形参的默认值问题:scala中定义的函数参数可以带有默认值,如果一旦函数的参数带有默认值,那么调用函数时,带有默认值的参数就可以不用传递数据了
* 一般要求默认值形参位于形参列表的最后,如果位于第一位,那么不具备默认值的形参需要通过具名实参的方式传递参数
* 函数的第三个问题:函数的返回值问题
* 函数的返回值可以是任何一种数据类型 Unit代表无返回值的 Nothingd
*/
class Demo11 {
def demo(studentName:AnyVal*):Unit={
/**
* 增强的for循环 <- 直接跟上一个集合
*/
for (elem <- studentName) {
println(elem)
}
}
/**
* 形参的默认值
*/
def write(line:String,append:Boolean = true):Unit={
println(line)
}
/**
* 形参的默认值
*/
def write1(append: Boolean = true,line: String): Unit = {
println(line)
}
/**
* 无正常返回值的函数
*/
def test():Nothing={
throw new IOException();
}
}
object Demo11{
def main(args: Array[String]): Unit = {
val demo11 = new Demo11();
demo11.demo(1,2,3)
demo11.write("zs")
demo11.write("zs",false)
demo11.write1(line = "zs")
val a = demo11.test();
}
}
【注】在Scala中,函数是一等公民,函数可以在Scala的任何位置充当任何的角色,函数可以声明在类中,也可以声明在函数中,还可以声明在参数列表中、还可以当作返回值,还可以当作一个变量
函数当变量使用:把函数重命名了
var d:函数的定义 = 函数名 _
【注意】函数的类型如何声明: (形参类型列表) => 返回值类型
示例:
函数的定义: def test(a:Int,b:Int):Int={a+b}
函数的类型写法:(Int,Int) => Int
package function
/**
* 函数的高阶使用
*/
object Demo01 {
def main(args: Array[String]): Unit = {
/**
* 1、函数充当变量使用
* test _ 将函数整体赋值给一个变量
*/
def test(a:Int,b:Int):Int={a+b}
def test1(a:String,b:Int){}
/**
* 此时a是一个函数的类型
* Scala中函数类型定义语法:(参数类型列表) => 函数的返回值类型
*/
var a:(Int,Int) => Int = test _
var b:(String,Int) => Unit = test1 _
println(a(1,2))
println(test(1,2))
}
}
函数当参数来使用
语法: def test(a:Int,f:(Int,Int)=>Int):Unit={
}
package function
/**
* 函数的高阶使用:函数当作参数来使用
*/
object Demo02 {
/**
* 要求 输入三个参数,其中前两个参数要根据第三个参数提供的函数计算出一个Int类型的值
*
* @param a
* @param b
* @param f
*/
def test(a:Int,b:Int,f:(Int,Int) => Int):Unit={
val result:Int = f(a, b)
println(result)
}
def main(args: Array[String]): Unit = {
/**
* 想让test函数计算a和b的最大值
*/
def max(a:Int,b:Int):Int={
if (a>b)
a
else
b
}
test(1,2,max _)//2
test(1,2,(a:Int,b:Int)=>{a+b})//3
test(1,2,(a,b)=>{a+b})//3
test(1,2,(a,b)=>a+b)//3
test(1,2,_+_)//3
}
}
函数当作返回值来使用
语法: def test():(Int,Int)=>Int={
}
package function
/**
* 函数的高阶使用--函数充当返回值
*/
object Demo03 {
def test(): (Int,Int)=>Int = {
def demo(a:Int,b:Int):Int={
a+b
}
return demo _
return (a:Int,b:Int)=>{a+b}
return (a,b)=>{a+b}
return (a,b)=>a+b
return _+_
}
}
def test(a:Int,b:Int):Int = {
a+b
}
var f1:(Int,Int)=>Int = test _
var f2:(Int,Int)=>Int = (a:Int,b:Int) => {a+b} //使用匿名函数
var f3:(Int,Int)=>Int = _ + _
函数的闭包问题
函数闭包指的是将不属于本函数的变量或者对象也包含进来,直到该函数运行完成,外部变量或者对象才可以被释放。
package function
object Demo04 {
def main(args: Array[String]): Unit = {
var x:Int = 1
def test(a:Int):Int={
a*x
}
test(1)
}
}
函数的柯里化
将一个接收多个参数的函数给他转换成为一个接收单个参数的函数的过程
将一个接收多个参数的函数转换成为一个返回了函数的函数,返回的函数传递的值就是原先的第二个参数
其实是闭包的一个使用场景
package function
/**
* 函数的柯里化
* test(1,2)
* test(1)(2)
*/
object Demo05 {
def sum(a:Int,b:Int,c:Int):Int={
a+b+c
}
def sum1(a:Int):Int=>Int=>Int={
def sum2(b:Int):Int=>Int={
def sum3(c:Int):Int={
a+b+c
}
return sum3 _
}
return sum2 _
}
def test(a:Int,b:Int=1):Int={
a*b
}
/**
* test1函数返回的是一个函数 函数的类型是Int=>Int
* 返回的函数的输入参数是原先函数的第二个参数
* 返回的函数的输出是原先函数的计算结果类型
* @param a
* @return
*/
def test1(a:Int):Int=>Int={
(b:Int)=>{a*b}
}
def main(args: Array[String]): Unit = {
var r:Int = test(1,2)
println(r)
var r1:Int = test1(1)(2)
println(r1)
sum(1,2,3)
var r2:Int = sum1(1)(2)(3)
println(r2)
}
}
案例:
def test1(a:Int,b:Int,c:Int,d:Int):Int={
a+b+c+d
}
def sum1(a:Int):Int =>Int =>Int => Int = {
def sum2(b:Int):Int =>Int => Int = {
def sum3(c:Int):Int =>Int = {
def sum4(d:Int):Int = {
a+b+c+d
}
sum4 _
}
sum3 _
}
sum2 _
}
var sum:Int = sum1(1)(2)(3)(4)
var sumT:Int = test1(1,2,3,4)
println(sum + " " + sumT)/
递归函数
函数内部调用本函数
递归三要素
package function
object Demo06 {
def main(args: Array[String]): Unit = {
/**
* 定义一个函数 求∑100
*/
var r = sum(1000000)
println(r)
}
def sum(a:Int):Int={
if(a == 1){
1
}else{
a+sum(a-1)
}
}
}
函数调用的惰性加载
惰性加载指的是将函数的调用延迟到第一次使用函数的返回值的时候才会调用
使用语法: lazy val 变量名 = 函数名(实参)
此时函数的调用在第一次使用变量的时候才会调用
一旦惰性加载,变量名只能使用val修饰
package function
object Demo07 {
def sum(a:Int,b:Int):Int = {
println("sum函数执行了")
a+b
}
def main(args: Array[String]): Unit = {
//函数的调用被惰性加载了
lazy val a = sum(1,2)
println("main函数中sum函数调用之后的输出")
println(a)
}
}
声明的简化
def test:Unit={}
调用的简化:一般不建议使用,建议运算符的函数调用简化
/**
* 函数的简化操作:
* Scala信奉一个原则:至简原则
* 函数基于这个原则,我们就可以进行相应的简化:简化可以从声明和调用两个层面简化
* 声明的简化规则:
* 1、如果函数的参数没有 那么()可以省略
* 2、函数的返回值不用加,可以根据函数的最后一行自动推断,最后一行返回的数据return关键字可以省略的 如果return没有省略 那么返回值类型一定要写上的
* 3、如果函数的返回值是unit类型的,那么返回值类型和=号都可以省略
* 4、如果函数的函数体只有一行 那么{}可以省略
* 5、如果函数名没有意义,那么函数名可以省略的(函数充当参数或者返回值使用的--高阶函数用法)
*
* 调用的简化规则:
* 1、如果函数没有参数,那么调用的时候 括号可以加也可以不加,但是如果函数声明的时候没有加括号 那么调用的时候一定不能加括号
* 2、调用函数的时候 点可以省略的 如果参数只有一个 调用的时候()可以省略
*/
object Demo12 {
def main(args: Array[String]): Unit = {
test
Demo12 test4 1;
}
/**
* 没有参数可以不用加括号
*/
def test:Unit={}
def test1(a:Int,b:Int):Int={
return a+b
}
def test2{}
def test3(a:Int,b:Int)=a+b
def test4(a:Int){}
}
Scala源于Java中,因此在Scala中也存在面向对象编程思想,面向对象编程最核心的逻辑就是以类来组织代码,以对象来调用代码。Scala的面向对象和Java基本上思维是一致的,只不过就是语法稍微不一样而已。
包package:包是用来分类管理Scala代码的,将不同类型的代码放到不同的包下,便于我们管理
Scala包有两种管理代码的方式
采用和Java一样的管理机制,新建包,包下可以新建类和子包
采用包对象的管理机制,实现一个文件中存在多个包和多个scala类
package com{
package nuckl{
class B{
}
}
class A{
}
}
Scala中类的导入问题import
在当前Scala类中,如果要使用非本包下的代码,那么我们就得需要通过import关键字导入才能使用。
每一个Scala类默认导入三个包
Scala类中导入有一些规则和Java有点不一样
package importstudy
import java.util.{Date, Scanner}
import java.sql.{Date => SQLDate}
/**
* 导包的规则
*/
class Demo01 {
def test():Unit = {
var sc = new Scanner(System.in);
var d = new Date()
var f = new SQLDate(1)
}
}
类的定义
访问控制修饰符 class className 访问控制修饰符(主构造器参数列表){
类体
}
访问控制符:三个 private protected public(不写)
在同一个Scala文件中可以存在多个Scala类,权限没要求的
属性用来描述类的特征
声明语法:访问控制修饰符 var|val 属性名:属性类型 = 值;
属性声明的时候必须加值,但是我不想给其他值,只想给默认值,那么值使用_ 来代替
【注意】val修饰的属性 不能赋予_ 默认值,必须给一个显示的值
package classstudy
import scala.beans.BeanProperty
class Demo01 {
@BeanProperty var name:String = _
@BeanProperty val age:Int = 1
}
class Demo02{
}
object Demo02{
def main(args: Array[String]): Unit = {
var a:Demo01 = new Demo01()
var b:Demo02 = new Demo02()
println(a.getName)
a.setName("kkkk")
println(a.getName)
println(a.getAge)
println(a)
}
}
属性前加一个注解@BeanProperty
方法就是函数,函数声明在类中,函数称之为方法
语法:
访问控制修饰符 def 方法名(形参列表):方法的返回值类型 ={
方法体
}
{} 类中类
构造器是创建该类的实例对象的
Scala有两种构造器
1、主构造器:声明在类上的 class ClassName 访问控制修饰符 (形参列表)–主构造器
2、辅助构造器:声明在类中的构造器,
语法:
def this(形参列表){
}
辅助构造器必须在首行直接或者间接的调用主构造器代码
【注意】
主构造器不存在构造体,那么也就意味着主构造器无法给属性赋值,为了可以给属性赋值,主构造器的形参列表有个变化,主构造器的形参列表可以使用var或者val修饰,一旦主构造器的形参使用var val修饰 那么主构造器中的形参就是类的属性了
主构造器我们一般都是要求是无参构造器,而且主构造器一旦是无参的,那么主构造器的()可以省去
package constructor
class People private ( var name:String,var age:Int){
def this(name:String){
this(name,1)
}
}
class Student private{
}
object People {
def main(args: Array[String]): Unit = {
val people = new People("zs",21)
println(people.name)
println(people.age)
//val people1 = new People("zs")
}
}
对象的创建就是变量|常量的定义
var|val 对象名:类 = new 类名(实参)
简化:类型可以省略,自动推断;如果调用的构造器的实参为空,那么()也可以省略的。
封装性
和Java的封装一样的概念,合理隐藏、合理暴露,控制类、属性、方法、构造器、内部类能被谁访问使用,不能被谁访问使用。
Scala的封装权限只有三种:private protected 不写(public)
封装性和Java的区别在于两个地方
package encapsulation.demo
class Demo01 private[encapsulation]{
}
====================================================
package encapsulation.demo01
import encapsulation.demo.Demo01
object Demo02 {
def main(args: Array[String]): Unit = {
val d = new Demo01()
println(d)
}
}
继承性
和Java的概念是一样的,extends继承,Scala也是单继承,一旦继承父类,拥有父类中非私有化的属性和方法。
package inheritance
class Father {
private var name:String = _
protected var age:Int = _
var sex:String = _
private def test1(): Unit = {
}
protected def test2(): Unit = {
}
def test3(): Unit = {
}
}
class Son extends Father{
}
object Son{
def main(args: Array[String]): Unit = {
var son = new Son();
println(son.age)
println(son.sex)
son.test2()
son.test3()
}
}
多态性
定义变量的时候,分为编译时类型和运行时类型
向上转型:将儿子的对象给了父类的变量引用,可以直接给,不需要任何多余的操作。
var s:Father = new Son()
向下转型:将父亲给儿子,不能直接给,需要使用asInstanceof[子类] 赋值,要求父亲的运行时类型必须是儿子或者儿子的子类类型。
var s:Father = new Son()
var s1:Son = s.asInstanceof[Son]
如果我们要进行向下转型,最好先使用Scala提供的以下代码先判断父类的运行时类型是不是子类的类型。
对象名.isInstanceof[ClassName]
classof[类名] 获取一个类的运行时类 返回的是一个Class类的对象
object Son{
def main(args: Array[String]): Unit = {
/**
* 向上转型可以直接转换
*/
var son:Father = new Son()
son.test3()
/**
* 向下转型 需要强转 asInstanceof[Son]
*/
var son1:Son = son.asInstanceOf[Son]
println(son1)
var son2:Father = new Father()
if(son2.isInstanceOf[Son]){
var son3: Son = son2.asInstanceOf[Son]
println(son3)
}else{
println("son2不是Son的类型,无法向下转型")
}
}
}
package review
class Demo02{
}
object Demo02 {
def main(args: Array[String]): Unit = {
var a = new Demo02
val clazz = a.getClass
println(clazz)//class review.Demo02
val value: Class[Demo02] = classOf[Demo02]
println(value)//class review.Demo02
}
}
抽象性
抽象类
abstract class ClassName{
抽象属性 抽象方法
}
抽象属性
抽象方法
Scala中非抽象子类重写抽象类的属性和方法时,为了表示重写的概念,加了override关键字表示重写的过程
package abstractstudy
abstract class Animal (){
//抽象属性 抽象属性也是要被非抽象子类重写的
var name:String
var age:Int = 1
//抽象方法 就是没有函数体的方法
def test():Unit
def test1():Unit={
}
}
class Dog extends Animal{
override var name: String = _
override def test(): Unit = {
}
}
object Dog{
def main(args: Array[String]): Unit = {
val dog = new Dog
dog.test()
println(dog.name)
// val animal = new Animal();
}
}
Scala中伴生对象Object
Object定义的属性和方法就是当前Class类的静态内容,静态内容可以直接使用类名来调用
Object类中存在一个功能特别强大的方法,apply方法
apply方法可以让我们创建对象的时候不需要使用new关键字,而是直接使用类名(形参列表)的形式构建类的对象。
def apply(形参列表):Class ={
new ClassName(实参);
}
package objectstudy
import objectstudy.Demo01.age
class Demo01 {
def this(name:String){
this()
this.name = name
}
var name:String = _
def test():Unit = {
println(age)
test()
}
}
object Demo01{
def main(args: Array[String]): Unit = {
var d = Demo01()
var d1 = Demo01("kl")
println(d1)
println(d1.name)
}
var age:Int = _
def test01():Unit={
//println(name)
}
def apply():Demo01 = {
new Demo01
}
def apply(name:String):Demo01={
new Demo01(name)
}
}
Scala中的case class样例类
样例类就等同于Java中JavaBean,同时Scala提供case class是为了丰富模式匹配的功能的。
样例类的语法
package objectstudy
import scala.beans.BeanProperty
object Demo02 {
def main(args: Array[String]): Unit = {
var p:People = new People("zs",20)
var p1:People = People("zs",20)
println(p)//People(zs,30)
println(p1)//People(ls,20)
println(p == p1)//true
println(p.getName)//zs
println(p.setName("kl"))//()
println(p.getName)//kl
}
}
case class People(@BeanProperty var name:String, age:Int){
}
package caseclass
abstract class Traffic{
}
case class Car(pinpai:String,pailiang:Double) extends Traffic
case class Plane(rongliang:Int) extends Traffic
/**
* 样例类和模式匹配的结合使用
*/
object Demo{
def judgeTraffic(traffic: Traffic):Unit = {
traffic match {
case Car(a,b) if b>1.2 => println(s"这是一个小汽车给,品牌是$a,排量是$b")
case Plane(c) => println(s"这是一个飞机,容量是$c")
case _ => println("这个交通工具不识别")
}
}
def main(args: Array[String]): Unit = {
var traffic:Traffic = Car("问界M7",1.0)
var traffic1:Traffic = Plane(6)
judgeTraffic(traffic)
judgeTraffic(traffic1)
}
}
Scala中的特质Trait
特质就是Java中的接口,只不过在Java中称之为接口,在Scala中称之为特质。Java中的所有接口都可以当作Scala的特质使用。
创建语法
trait 特质名{
抽象属性 抽象方法 普通的属性 普通的方法
}
使用
package traitstudy
trait FlyAble {
//抽象属性
var name:String
//抽象方法
def fly():Unit
//普通的属性
var age:Int = _
//普通方法
def test():Unit ={
}
}
class Animal{}
class Bird extends Animal with FlyAble with Comparable[Bird]{
override var name: String = _
override def fly(): Unit = {
}
override def compareTo(o: Bird): Int = {
return 1
}
}
Scala中可以使用Java的集合,但是Scala也给我们提供了一套集合体系,Spark Kafka既支持Scala集合体系,还支持Java集合体系。
不可变集合体系:每一次操作集合都是返回一个新的集合对象,而原有的集合不受任何的影响
包:scala.collection.immutable
可变集合体系:每一次操作集合都是对原有的集合对象进行操作,而不是返回新的集合对象
包:scala.collection.mutable
Scala中数组-Seq的使用
不可变数组:Array
可变数组:ArrayBuffer
package collection
import scala.collection.mutable.ArrayBuffer
/**
* 数组的定义和使用
*/
object ArrayStudy {
def main(args: Array[String]): Unit = {
/**
* 1、不可变数组的创建
* (1)new 创建
* (2)Array提供的伴生对象的apply方法来创建
*/
var array:Array[Int] = new Array[Int](10)
array(0) = 1
println(array(0))//1
var array1 = Array(1,2,3,4,5,6,7,8,9,10)
println(array1(1))//2
/**
* 2、可变数组 ArrayBuffer
*/
var ab:ArrayBuffer[Any] = ArrayBuffer[Any]()
ab.append(1)
ab.append(2)
ab.append(3)
println(ab)//ArrayBuffer(1, 2, 3)
/**
* 3、可变数组与不可变数组的互相转换
*/
array1.toBuffer //不可变数组转可变数组
ab.toArray //可变数组转不可变数组
/**
* 4、多维数组
*/
val array2:Array[Array[Int]] = Array.ofDim(2, 3)
println(array2(0)(1))//0
//数组的遍历
for(elem:Array[Int] <- array2;a <- elem){
}
for(i <- 0 to array2.length-1){
}
}
}
Scala中List列表的使用
不可变列表:List
可变列表:ListBuffer
package collection
import scala.collection.mutable.ListBuffer
object ListStudy {
def main(args: Array[String]): Unit = {
/**
* 1、不可变列表
* List的伴生对象的apply方法构建的
*/
var list:List[Int] = List[Int](1,2,3)
//:: list集合的一种特殊运算符 代表在集合的头部添加一个新的元素 而且会给我们返回一个新的集合
//:: 可以添加多个元素
list = 4 :: 5 :: 6 :: list//List(4, 5, 6, 1, 2, 3,)
//如果添加单个元素 使用 +: :+
list = list :+ 7//尾部添加
list = 8 +: list//头部添加 //List(8, 4, 5, 6, 1, 2, 3, 7)
var list1:List[Int] = List[Int](10,11)
//:::(扁平化操作) 将左边的集合中元素一个一个加到右边的集合中 而不是将左边的集合当作一个整体添加
list = list1 ::: list//List(10, 11, 8, 4, 5, 6, 1, 2, 3, 7)
println(list)//List(8, 4, 5, 6, 1, 2, 3, 7)
var list2 = 4 :: 5 ::List(1,2,3) :: Nil//List(4, 5, List(1, 2, 3))
var list3 = 4 :: 5 ::List(1,2,3) ::: Nil//List(4, 5, 1, 2, 3)
println(list3)
//移除左边的多少个元素
list3 = list3.drop(3)//List(2, 3)
list3 = list3.updated(0,22)//List(22, 3)
println(list3)
println(list3(0))//22
//遍历数组
list3.foreach((a:Int)=>{println(a)})//22 3
/**
* 可变ListBuffer
*/
var lb = ListBuffer[Int](1,2,3,4)
//添加数据
lb.append(5)//默认添加到末尾
lb.insert(1,6)//默认添加到开头
lb.+=(7)//默认添加到末尾
println(lb)//ListBuffer(1, 6, 2, 3, 4, 5, 7)
//移除数据
lb.remove(1)//移除目标索引的数据
lb.-=(1)//移除目标值 lb -= 1
println(lb)//ListBuffer(2, 3, 4, 5, 7)
//取值
println(lb(1))//3
//遍历元素 1、索引遍历 2、增强的for循环 3、foreach
lb.foreach(println)// 2 3 4 5 7
//修改数据
lb.update(1, 56)
println(lb)//ListBuffer(2, 56, 4, 5, 7)
}
}
Scala中Set集合的使用
不可变Set集合:Set
可变Set集合:Set
package collection
object SetStudy {
def main(args: Array[String]): Unit = {
/**
* 不可变的Set集合
*/
//1、创建不可变Set集合
var set:Set[Int] = Set[Int](1,2,3,4,5,1,2)//HashSet(5, 1, 2, 3, 4)
//2、set集合中添加数据
set = set + 6
//3、set集合删除数据
set = set - 1//HashSet(5, 6, 2, 3, 4) 减的是元素
println(set)
/**
* 可变的set集合
*/
var set1 = scala.collection.mutable.Set[Int](1,2,3,4,5,6,5,6)
//1、添加数据
set1.add(88)//HashSet(1, 2, 3, 4, 5, 6, 88)
set1 += 99//HashSet(1, 2, 3, 99, 4, 5, 6, 88)
//2、删除数据
set1.remove(88)//HashSet(1, 2, 3, 99, 4, 5, 6)
set1 -= 3//HashSet(1, 2, 99, 4, 5, 6)
println(set1)
}
}
Scala中元组Tuple
package collection
object TupleStudy {
def main(args: Array[String]): Unit = {
/**
* 元组是Scala中一种比较特殊的“集合”类型 元组也可以存放一组数据,但是这一组数据类型可以不一致
* 元组的存放的数据个数是有限制的,最小1个 最多22个
* 因此元组在Scala中有一个专业的叫法:一元组 .... 二十二元组
* Tuple1
* Tuple2
* ...
* Tuple22
*/
//元组的创建有三种方式:
var t1:Tuple2[String,Int] = new Tuple2[String,Int]("zs",20)
var t2:Tuple2[String,Int] = ("ww",20)
var t3:Tuple2[String,Int] = Tuple2[String,Int]("ls",20)
println(t1)//(zs,20)
println(t2)//(ww,20)
println(t3)//(ls,20)
var t4:Tuple3[Int,Int,Int] = (1,2,3)
println(t4)//(1,2,3)
//元组的类型有两种声明方式:TupleN[xxx,xxx] (xxx,xxx)
var t5:(String,Int) = new Tuple2[String,Int]("kl",20)
println(t5)//(kl,20)
/**
* 获取元组中元素
* 元组提供了一个属性 _x
* 在Scala当中map集合的kv可以当作二元组来处理(添加数据,foreach)
*/
println(t4._3)//3
println(t5._1)//kl
println(t5._2)//20
}
}
Scala中Map集合的使用
package collection
object MapStudy {
def main(args: Array[String]): Unit = {
/**
* 1、不可变的Map集合
*/
var map:Map[String,Int] = Map[String,Int]("zs"->20,"ls"->30,"kl"->20,"zs"->40)
println(map)//Map(zs -> 40, ls -> 30, kl -> 20)
//添加数据 添加数据 需要传入一个二元组 Tuple2
map = map + (("hyf",18))//Map(zs -> 40, ls -> 30, kl -> 20, hyf -> 18)
//删除数据
map = map.-("ls")//Map(zs -> 40, kl -> 20, hyf -> 18)
//更新数据
map = map.updated("kl",23)//Map(zs -> 40, kl -> 23, hyf -> 18)
// 获取key对应的value
val value1:Int = map.getOrElse("hyf", 10)//18
val value2:Int = map.getOrElse("ww", 999)//999
println(value2)
println(map)
//遍历
for(elem <- map.keys){
println(map.get(elem).get)//40 23 18
}
map.foreach((tuple:(String,Int)) => {println(s"key=${tuple._1} value=${tuple._2}")})
//key=zs value=40
//key=kl value=23
//key=hyf value=18
/**
* 2、可变的Map集合
*/
val map1 = scala.collection.mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
println(map1)//HashMap(a -> 1, b -> 2, c -> 3)
//向集合增加数据
map1 += ("d" -> 4)
println(map1)//HashMap(a -> 1, b -> 2, c -> 3, d -> 4)
// 将数值4添加到集合,并把集合中原值1返回
val maybeInt: Option[Int] = map1.put("a", 4)
println (maybeInt.getOrElse(0))//1
println(map1)//HashMap(a -> 4, b -> 2, c -> 3, d -> 4)
map1 += ("b" -> 44) // 这里会将键 "b" 的值更新为 44 或者添加一个新的键值对
println(map1)//HashMap(a -> 4, b -> 44, c -> 3, d -> 4)
//删除数据
map1.-=("b", "c")
println(map1)//HashMap(a -> 4, d -> 4)
//修改数据
map1.update("d", 5)
println(map1)//HashMap(a -> 4, d -> 5)
map1("d") = 66
println(map1)//HashMap(a -> 4, d -> 66)
//打印集合
map1.foreach((kv) => {
println(kv)
//(a,4)
//(d,66)
})
}
}
基本函数
xxx.length —— 获取集合长度
xxx.size —— 获取集合大小
xxx.foreach(函数) —— 循环遍历
xxx.mkString(“分隔符”) —— 生成字符串
xxx.contains(xxxx) —— 是否包含
xxx.iterator ——迭代器
package collection
import scala.collection.mutable.ListBuffer
object Demo01 {
def main(args: Array[String]): Unit = {
/**
* 测试集合的常用基本函数
*/
var list1 = List[Int](1,2,3,4,5)
println("-------不可变List-------")
println(list1.length)
println(list1.size)
list1.foreach((a:Int)=>println(a))
list1.foreach(println)//简化形式
println(list1.mkString("=="))
println(list1.contains(1))
var list2 = ListBuffer[Int](1,2,3,4,5)
println("-------可变List-------")
println(list2.length)
println(list2.size)
list2.foreach((a: Int) => println(a))
list2.foreach(println) //简化形式
println(list2.mkString("=="))
println(list2.contains(1))
var map = Map[String, Int]("zs" -> 20, "ls" -> 20)
println("-------可变Map-------")
println(map.size)
map.foreach(println)
println(map.mkString("=="))
println(map.contains("zs"))
}
}
集合的一些高级函数
获取集合的头 head()
获取集合的尾(不是头的就是尾) tail
集合最后一个数据
集合初始数据(不包含最后一个)
反转
取前(后)n 个元素
去掉前(后)n 个元素
并集
交集
差集
拉链
滑窗
package collection
/**
* 集合的高级函数
*/
object Demo02 {
def main(args: Array[String]): Unit = {
var list = List[Int](1,2,3,4)
println(list.head)
println(list.tail)
println(list.last)
println(list.init)
println(list.reverse)
println(list.take(2))
println(list.takeRight(3))
println(list.drop(1))
println(list.dropRight(1))
var list1 = List[Int](4,5,6,7,8,9)
println(list.union(list1))
println(list.concat(list1))
println(list.intersect(list1))
println(list.diff(list1))
println(list1.diff(list))
var col:List[(Int,Int)] = list.zip(list1)
println(col)
/**
* 滑窗
*/
var list2 = List[Int](1,2,3,4,5,6,7,8,9,10,11,12,13)
var list3:Iterator[List[Int]] = list2.sliding(3,1)
while(list3.hasNext){
println(list3.next())
}
}
}
集合的计算函数
sum求和
求乘积
最大值
最小值
排序
sorted(implicit ord: Ordering[B]):根据当前集合中的元素进行大小比较 然后去排序,前提是集合中的元素必须是可以比较大小的,如果不能比较大小,那么需要传递一个比较器,比较器返回一个int类型的值
sortedBy(f: xx=>xxx)((implicit ord: Ordering[xxx])):将集合中元素转换称为另外一种类型 然后根据转换的类型做比较
sortWith(f:(xx,xx)=>Boolean): 自定义元素的比较规则,返回一个boolean类型的值
package collection
class People(var name: String ,var age: Int ){
override def toString: String = s"People{name=$name,age=$age}"
}
object People{
def main(args: Array[String]): Unit = {
var p1 = new People("zs",20)
var p2 = new People("ls",30)
var p3 = new People("ww",18)
var list:List[People] = List[People](p1,p2,p3)
println(list)
var list1 = list.sorted(new Ordering[People] {
override def compare(x: People, y: People): Int = {
if (x.age > y.age){
1
}else{
-1
}
}
})
println(list1)
var list2 = list.sorted((x:People,y:People)=>{
if (x.age>y.age){
1
}else{
-1
}
})
println(list2)
var list3 = list.sorted((x:People,y:People)=>x.age-y.age)
println(list3)
val list4 = list.sortBy((x: People) => x.age)
println(list4)
var list5 = list.sortWith((x:People,y:People)=>{
if (x.age>y.age){
true
}else{
false
}
})
println(list5)
}
}
package collection
/**
* 集合的计算函数
*/
object Demo03 {
def main(args: Array[String]): Unit = {
var list = List[Int](1,3,4,5)
println(list.sum)
println(list.product)
println(list.max)
println(list.min)
val list1 = list.sorted
val list2 = list.sortBy((a: Int) => a)
println(list1)
println(list2)
println(list.sortWith((a:Int,b:Int)=>a>b))
}
}
扩展类的功能的,让原本两个毫无关系的类,也可以互相调用里面的方法,隐式转换的内容会自动触发
implicit def 函数名(类型):另外一个类型={
如何创建另外一个类型
}
将输入类型转换称为输出类型,从而扩展某个类型的功能和方法
package implicstudy
class Demo {
def run():Unit= {
}
}
class Demo01{
def call():Unit={
println("call方法执行了")
}
}
object Demo{
def main(args: Array[String]): Unit = {
implicit def test(demo:Demo):Demo01 ={
new Demo01()
}
var demo = new Demo()
demo.call()
}
}
package implicstudy
class Test {
def haha():Unit={
println("haha执行了")
}
}
object Test{
def main(args: Array[String]): Unit = {
implicit def xxx(a:Any):Test = {
new Test
}
var a:Int = 1
a.haha()
var b:Boolean = true
b.haha()
}
}
可以实现在调用参数的时候,哪怕参数没有默认值,也可以不用传递,也能调用函数
如果使用隐式转换参数,需要做两步操作
package implicstudy
object Demo02 {
def test(implicit name:String):Unit={
println(name)
}
def main(args: Array[String]): Unit = {
implicit var name = "zs"
//implicit var name1 = "zs"
test
}
}
(1)其所带的构造参数有且只能有一个
(2)隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。
1、_ 在模式匹配中,_代表的是未匹配到其他情况,默认情况
2、函数名 _ : _代表的是将函数当作一个整体来使用,而非调用函数
3、导包的时候_有两种用途
4、声明属性的时候,属性值可以使用_替代:此时_代表给属性赋予默认值