Scala基础(一)

一、基础语法

1、Scala与Java的关系

  • Scala是基于Java虚拟机,也就是JVM的一门编程语言
  • 所以Scala的代码,都必须经过编译为字节码,然后交由Java虚拟机运行
  • Scala和Java是可以无缝操作的,Scala可以任意调用Java的代码

2、安装

  • 官方下载: http://www.scala-lang.org/download/
  • 在windows命令行内即可直接键入scala,打开scala命令行,进行scala编程。
    在这里插入图片描述

3、解释器

  • REPL: Read(取值)->Evaluation(求值)->Print(打印)->Loop(循环)。
    Scala解释器也被称为REPL,会快速编译Scala代码为字节码,然后交给JVM执行。
  • 计算表达式: 在Scala>命令行内,键入Scala代码,解释器会直接返回结果,如果没有指定变量来存放这个值,默认值为res,而且会显示结果的数据类型,比如Int、Double、String等。
    在这里插入图片描述
  • 内置变量: 在后面可以继续使用res这个变量,以及它存放的值。
    在这里插入图片描述
  • 自动补全: Tab键

4、声明变量

1)val变量(常量)

可以声明变量用来存放表达式的计算结果,值无法改变,但是可以继续使用
在这里插入图片描述

2)var变量(变量)

声明变量,值可以改变,通常不建议使用
在这里插入图片描述
在Java的大型复杂系统的设计和开发中,也使用了类似的特性,我们通常会将传递给其他模块 / 组件 / 服务的对象,设计成不可变类(Immutable Class)。在里面也会使用java的常量定义,比如final,阻止变量的值被改变。从而提高系统的健壮性(robust,鲁棒性)和安全性。

3)指定类型

声明变量可以手动指定类型,如果不指定会自动根据值进行类的推断
在这里插入图片描述

4)声明多个变量

在这里插入图片描述

5、数据类型与操作符

1)基本数据类型

Byte、Char、Short、Int、Long、Float、Double、Boolean

  • Scala与Java的基本数据类型大致相同,但是没有基本数据类型与包装类型的概念,统一都是类。
  • Scala自己会负责基本数据类型和引用类型的转换操作
  • 使用以上类型,直接就可以调用大量函数

2)类型的加强板类型

  • Scala类使用很多加强类给数据类型增加了上百种增强的功能或函数。
  • String类通过StringOps类增强了大量的函数

#例:取相同的字母
在这里插入图片描述

  • Scala还提供了RichInt、RichDouble、RichChar等类型,RichInt就提供了to函数,1.to(10),此处Int先隐式转换为RichInt,然后再调用其to函数

3)基本操作符

  • scala的算术操作符与java的算术操作符也没有什么区别,比如+、-、*、/、%等,以及&、|、^、>>、<<等。
  • 但是,在scala中,这些操作符其实是数据类型的函数,比如1 + 1,可以写做1.+(1)
    在这里插入图片描述
  • scala中没有提供++、–操作符,我们只能使用+和-,比如counter = 1,counter++是错误的,必须写做counter += 1.

6、函数调用与apply()函数

1)函数调用方式

在这里插入图片描述
如果调用时,不需要传递参数,则Scala允许调用时省略括号
在这里插入图片描述

2)apply函数

  • Scala中的apply函数是非常特殊的一种函数,在Scala的object中,可以声明apply函数。而使用“类名()”的形式,其实就是“类名.apply()”的一种缩写。通常使用这种方式来构造类的对象,而不是使用“new 类名()”的方式。
  • 例如,“Hello World”(6),因为在StringOps类中有def apply(n: Int): Char的函数定义,所以"Hello World"(6),实际上是"Hello World".apply(6)的缩写。
    在这里插入图片描述
  • 例如,Array(1, 2, 3, 4),实际上是用Array object的apply()函数来创建Array类的实例,也就是一个数组。
  • 在这里插入图片描述

二、条件控制与循环

1、if表达式

1)定义

在Scala中,if表达式是有值的,就是if或者else中最后一行语句返回的值。

  • 例如,val age = 30; if (age > 18) 1 else 0
    在这里插入图片描述
  • 可以将if表达式赋予一个变量,例如,val isAdult = if (age > 18) 1 else 0
    在这里插入图片描述
  • 另外一种写法,var isAdult = -1; if(age > 18) isAdult = 1 else isAdult = 0,但是通常使用上一种写法
    在这里插入图片描述

2)if表达式的类型推断

由于if表达式是有值的,而if和else子句的值类型可能不同,此时Scala会自动进行推断,取两个类型的公共父类型。

  • 表达式的类型是Int,因为1和0都是Int
    在这里插入图片描述
  • if和else的值分别是String和Int,则表达式的值是Any,Any是String和Int的公共父类型
    在这里插入图片描述
  • 如果if后面没有跟else,则默认else的值是Unit,也用()表示,类似于java中的void或者null
    在这里插入图片描述

3)将if语句放在多行中

默认情况下,REPL只能解释一行语句,但是if表达式通常需要放在多行。
可以使用{}的方式,或者使用:paste和ctrl+D的方式。
在这里插入图片描述

2、语句终结符、块表达式

默认情况下,scala不需要语句终结符,默认将每一行作为一个语句

1)一行放多条语句

如果一行要放多条语句,则必须使用语句终结符
#例:使用分号作为语句终结符
在这里插入图片描述
#通常来说,对于多行语句,还是会使用花括号的方式
在这里插入图片描述

2)块表达式

指的就是{}中的值,其中可以包含多条语句,最后一个语句的值就是块表达式的返回值。
在这里插入图片描述

3、输入和输出

1)print和println

print打印时不会加换行符,而println打印时会加一个换行符
在这里插入图片描述

2)printf

格式化
在这里插入图片描述

3)readLine

从控制台读取用户输入的数据,类似于java中的System.in和Scanner
在这里插入图片描述

4)综合案例

游戏厅门禁
在这里插入图片描述

4、循环

1)while do 循环

基本语义与Java相同
在这里插入图片描述

2)Scala没有for循环,只能使用while替代for循环,或者使用简易版的for语句

  • 简易版for语句
    在这里插入图片描述
  • until,表达式不达到上限
    在这里插入图片描述
  • 对字符串进行遍历,类似于Java的增强for循环
    在这里插入图片描述

3)跳出循环语句

scala没有提供类似于java的break语句,但是可以使用boolean类型变量、return或者Breaks的break函数来替代使用。
在这里插入图片描述

5、高级for循环

1)多重for循环

九九乘法表
在这里插入图片描述

2)if守卫:取偶数

在这里插入图片描述

3)for推导式:构造集合

在这里插入图片描述

三、函数入门

1、函数的定义与调用

在Scala中定义函数时,需要定义函数的函数名、参数、函数体
在这里插入图片描述
Scala要求必须给出所有参数的类型,但是不一定给出函数返回值的类型,只要右侧的函数体中不包含递归的语句,Scala就可以自己根据右侧的表达式推断出返回类型。

2、在代码块中定义包含多行语句的函数体

单行的函数:
在这里插入图片描述
如果函数体中有多行代码,则可以使用代码块的方式包裹多行代码,代码块中最后一行的返回值就是整个函数的返回值。与Java中不同,不是以return为返回值。

#累加功能:
在这里插入图片描述

3、递归函数与返回类型

如果在函数体内递归调用函数自身,则必须手动给出函数的返回类型

#例:斐波那契数列:9 + 8; 8 + 7 + 7 + 6; 7 + 6 + 6 + 5 + 6 + 5 + 5 + 4; …
在这里插入图片描述

4、参数

1)默认参数

在Scala中,有时我们调用某些函数时,不希望给出参数的具体值,而希望使用参数自身默认的值,此时就定义在定义函数时使用默认参数。
在这里插入图片描述
如果给出的参数不够,则会从左往右依次应用参数。

Java与Scala实现默认参数的区别

Java

public void sayHello(String name, int age) {
  if(name == null) {
    name = "defaultName"
  }
  if(age == 0) {
    age = 18
  }
}
sayHello(null, 0)

Scala
在这里插入图片描述

2)带名参数

在调用函数时,也可以不按照函数定义的参数顺序来传递参数,而是使用带名参数的方式来传递。

3)变长参数

在Scala中,有时我们需要将函数定义为参数个数可变的形式,则此时可以使用变长参数定义函数。
在这里插入图片描述

使用序列调用变长参数

  • 不能将一个已有的序列直接调用变长参数
    在这里插入图片描述
  • 需要使用Scala特殊的语法将参数定义为序列,让Scala解释器能够识别
    在这里插入图片描述
    案例:使用递归函数实现累加
    在这里插入图片描述

5、过程

在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用=连接,则函数的返回值类型就是Unit。这样的函数就被称之为过程。

  • 过程通常用于不需要返回值的函数。
  • 过程还有一种写法,就是将函数的返回值类型定义为Unit。
    在这里插入图片描述

6、lazy值

如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用,比如打开文件进行IO,进行网络IO等。
在这里插入图片描述

  • 即使文件不存在,也不会报错,只有第一个使用变量时会报错,证明了表达式计算的lazy特性。

7、异常

异常处理和捕获机制与Java非常相似
在这里插入图片描述

四、数组

1、Array

  • 是长度不可改变的数组
  • scala和Java都运行在JVM中,双方可以相互调用,因此scala数组底层实际上是Java数组
  • 字符串数组在底层就是Java的String[],整数数组在底层就是Java的Int[]

// 数组初始化后,长度就固定下来了,而且元素全部根据其类型初始化
在这里插入图片描述
// 可以直接使用Array()创建数组,元素类型自动推断
在这里插入图片描述
//可以类型不同
在这里插入图片描述

2、ArrayBuffer

  • 类似于Java中的ArrayList这种长度可变的集合类

// 如果不想每次都使用全限定名,则可以预先导入ArrayBuffer类
在这里插入图片描述
// 使用ArrayBuffer()的方式可以创建一个空的ArrayBuffer
在这里插入图片描述
// 使用+=操作符,可以添加一个元素,或者多个元素
// 这个语法必须要谨记在心!因为spark源码里大量使用了这种集合操作语法
在这里插入图片描述
// 使用++=操作符,可以添加其他集合中的所有元素
在这里插入图片描述
// 使用trimEnd()函数,可以从尾部截断指定个数的元素
在这里插入图片描述
// 使用insert()函数可以在指定位置插入元素
// 但是这种操作效率很低,因为需要移动指定位置后的所有元素
在这里插入图片描述
// 使用remove()函数可以移除指定位置的元素
在这里插入图片描述
//删除角标是1到3的元素
在这里插入图片描述
// Array与ArrayBuffer可以互相进行转换
在这里插入图片描述

3、遍历Array和ArrayBuffer

// 使用for循环和until遍历Array / ArrayBuffer
// 使until是RichInt提供的函数
在这里插入图片描述
// 跳跃遍历Array / ArrayBuffer
在这里插入图片描述
// 从尾部遍历Array / ArrayBuffer
在这里插入图片描述
// 使用“增强for循环”遍历Array / ArrayBuffer
在这里插入图片描述

4、数组常见操作

// 数组元素求和
在这里插入图片描述
// 获取数组最大值
在这里插入图片描述
// 对数组进行排序
在这里插入图片描述
// 获取数组中所有元素内容
在这里插入图片描述
// toString函数
在这里插入图片描述

5、使用yield和函数式编程转换数组

// 对Array进行转换,获取的还是Array
在这里插入图片描述
// 对ArrayBuffer进行转换,获取的还是ArrayBuffer
在这里插入图片描述
// 结合if守卫,仅转换需要的元素
在这里插入图片描述
// 使用函数式编程转换数组(通常使用第一种方式)
在这里插入图片描述

6、算法案例:移除第一个负数之后的所有负数

// 构建数组
在这里插入图片描述
// 只要第一个负数,后边的不要了,结果:1, 2, 3, 4, 5, -1
在这里插入图片描述

算法案例:移除第一个负数之后的所有负数(改良版)

// 重新构建数组
在这里插入图片描述
// 每记录所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素
// 性能较高,数组内的元素迁移只要执行一次即可
//keepIndexes (0,1,2,3,4,5)
//a(keepIndexes(i))=Array(1,2,3,4,5,-1)
在这里插入图片描述
在这里插入图片描述

算法案例:移除第一个负数之后的所有负数(正负相间)

// 构建数组
// 空数组用来存放
在这里插入图片描述
// 每记录所有不需要移除的元素的索引,稍后一次性移除所有需要移除的元素
// 性能较高,数组内的元素迁移只要执行一次即可
在这里插入图片描述

五、Map与Tuple

1、创建Map

// 创建一个不可变的Map
在这里插入图片描述
// 创建一个可变的Map
在这里插入图片描述
// 使用另外一种方式定义Map元素
在这里插入图片描述
// 创建一个空的HashMap
在这里插入图片描述

2、访问Map的元素

// 获取指定key对应的value,如果key不存在,会报错
在这里插入图片描述
// 使用contains函数检查key是否存在
在这里插入图片描述
// getOrElse函数
在这里插入图片描述

3、修改Map函数

// 更新Map的元素
在这里插入图片描述
// 增加多个元素
在这里插入图片描述
// 移除元素
在这里插入图片描述
// 更新不可变的map
在这里插入图片描述
// 移除不可变map的元素
在这里插入图片描述

  • Array和ArrayBuffer可变还是不可变是指的长度
  • Map的可变与不可变是指的Map中是值

4、遍历Map

// 遍历map的entrySet
在这里插入图片描述
// 遍历map的key
在这里插入图片描述
// 遍历map的value
在这里插入图片描述
// 生成新map,反转key和value
在这里插入图片描述

5、SortedMap和LinkedHashMap

// SortedMap可以自动对Map的key的排序
在这里插入图片描述
// LinkedHashMap可以记住插入entry的顺序
在这里插入图片描述

6、Map的元素类型—Tuple

// 简单Tuple
在这里插入图片描述
// 访问Tuple
t._1
// zip操作(拉链操作)
在这里插入图片描述


版权声明:本文为wangzhangni原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。