Scala是一门主要以Java虚拟机(JVM)为目标运行环境,并将面向对象和函数式编程有机的结合在一起。因为Scala运行于JVM上,所以Scala可以访问任何Java类库,并且能够与Java框架进行互操作。Scala既有动态语言的灵活简洁(通过类型推到),又有静态类型检查带来的安全保证和执行效率(Scala是静态类型语言)。Scala支持处理脚本化的临时任务,也能处理高并发场景下的分布式互联网大数据应用程序。
扩展
动态类型和静态类型
动态类型语言:运行期间才做数据类型检查。在动态类型语言编程中,不用给变量指定数据类型。该语言会在第一次赋值的时候,在内部将数据类型记录下来。比如:Python、JavaScript、PHP等。
静态类型原因:编译期间就做类型检查。在编程期间需要指定数据类型(有些需要手动指定比如Java,有些语言会隐式转换,比如Scala),变量在使用之前必须声明了数据类型。比如Java、Scala、C、C++等。
动态类型语言和静态类型语言最大的区别就是数据类型在编译期间是否确定。
强类型和弱类型
强定义类型语言:强制数据类型定义的语言,一旦将变量赋值给某个数据类型,如果不经过强制类型转换,那么永远都是这个类型。它是类型安全的。比如Java、Scala、C。
弱定义类型语言:数据类型是可以被忽略的,与强制类型语言相反,一个变量可以赋值给不同类型的语言。它是类型不安全的。比如Python、JavaScript等。
强定义类型语言和弱定于类型语言的最大求别就是一个变量能不能被赋值给多个数据类型。
变量
变量定义
Scala提供了两种声明变量的方式:val和var。其中val类似java中的final变量,定义后不可重新赋值(对象类型,对象本身不能重新赋值,但是对象内部是可以重新赋值的),var定义的变量是可重复赋值的变量。
Scala定义变量不需要显示指定类型, 因为Scala内部的类型推断会根据值内容推断,当然也可以指定类型。
代码块
Plain Text
val num1 = 1
va2 num2: Int = 2
提示
在Scala中,变量或函数的类型都是在变量或函数的后面,这使得我们在阅读复杂类型的声明时更加容易。
还有一点需要注意,在变量声明和赋值语句之后,并没有分号。在Scala中仅当同一行存在多条语句时才需要使用分号分隔。
Scala变量定义时必须进行初始化操作(无论val还是var类型变量),var类型变量可以使用占位符在定义时赋值,但是需要指定数据类型。
代码块
Scala
var num: Int = _ //初始化为0
var str: String = _ //初始化为null
基本类型
Scala同Java一样也有七种数值类型:Byte、Short、Int、Long、Float、Double和Boolean。不同的是,这些类型在Scala中都是类,Scala并没有刻意区分基本类型和引用类型,所以从这方面来看Scala面向对象的更加纯粹。这些基本类型都在scala包中,比如scala.Int、scala.Double(Scala默认会加载scala和java.lang包)。
Scala使用底层的java.lang.String类来表示字符串,但是Scala提供了扩展类StringOps为字符串追加了上百种操作,比如:
代码块
Plain Text
"Hello".intersect("World") //求两个字符串的交集。
同理,Scala为基本类型分别都提供了扩展类:RichInt、RichDouble、RichChar等,由基础类型到扩展类型的使用是Scala内部隐式转换完成的,我们不需要做任何操作(在看API时,可以看一下扩展类型提供的方法)。
提示
在Scala中进行类型转换时是使用方法,而不是强制类型转换。比如3.14.toInt 得到3。
懒值
当我们在val类型前使用lazy修饰时,这个变量的初始化会被延迟,直到我们首次使用它。
代码块
Scala
//变量只有在第一次使用时才会打开文件
lazy val words = scala.io.Source.fromFile("/opt/shard/a.log").mkString
Scala只允许在val类型变量前使用lazy,对于var变量不适用,因为避免程序运行中变量还未使用就被重新赋值。
运算符
Scala也适用+、-、*、/、%进行算术操作,使用&、|、^、>>、<<、~进行位操作,使用<、<=、>、>=、!进行关系运算操作,使用&&、||进行逻辑运算操作(也有短路概念)。与Java不同的是,这些运算符都是方法调用,比如1+ 2实际调用的是 1.+(2),当a.ope(b)的时候ope称做方法,当写成 a ope b的时候ope就称做操作符,这些运算符称为中缀运算符。
Scala并没有提供++和--操作符,可以使用 +=1 和-=1来代替(因为对于Int是一个类,Scala认为没有必要为了这么一个功能,来增加一些特例)。
控制结构
在Java中表达式和语句是两类,表达式有值,而语句执行动作。但在Scala中,几乎所有构造的结构语句都有值。
条件表达式
Scala的if/else语法结构和Java一样,但是Scala中的if/else表达式是有值的。
代码块
Plain Text
//java形式的赋值
int res;
if(x > 0) res = 1 else res = -1;
//scala 简易赋值
val res = if(x > 0) 1 esle -1
Scala还做了一点,就是将Java中if/else和? : 三目运算结合起来了。如果要实现下面功能,java只能通过三目运算符来实现。
代码块
Plain Text
val res = if(x > 0) "yes" : -1
//缺少else语句
val res = if(x > 0) "yes"
val res = if(x > 0) "yes" else ()
if/else语句的两个分支分别为String和Int,它们的超类为Any,所以res的类型为Any类型。因为Scala每个表达式都应该有值,当缺少else语句时表达式的值就不能确定了,Scala引入了Unit类,写作(),来表示“无有用值”的占位符(和java中的void类似,但本质上void表示没有值,而Unit表示无有用的值)。
注意
Scala没有Switch语句,但是提供了功能强大的模式匹配。
循环
Scala提供了和Java一样的while和do-while循环。
代码块
Scala
while(n > 0) {
//循环体
}
do{
//循环体
}while(n > 0);
Scala也提供了for循环,但是并不是Java中的for循环不一样。用变量i来遍历右侧表达式中的所有值,变量i并没有通过val和var指定,它的类型是集合元素的类型,作用域持续到循环结束。
代码块
Scala
for(i <- 表达式){
//循环体
}
说明
Scala并没有提供break和continue语句,如果要退出循环,可以使用以下几种方式:
1、使用boolean类型控制变量。
2、使用嵌套函数,从函数中return。
3、使用Breaks对象中的break方法。
代码块
Scala
import scala.util.control.Breaks._
breakable{
for(...) {
if(...) break
}
}
方式3是通过抛出和捕获异常来完成的,所以效率会低一些。
还需要指出的一点,在Java中不能在重叠的作用域中使用同名的两个变量,当在Scala中这是允许的。
代码块
Scala
val n = ...
for(n <- 1 to 10) {
//使用for语句中的n
}
for循环高级用法
可以在for循环中提供多个生成器,使用分号分开。多个生成器相当于多层for循环,从左到右依次由外到内的多层for循环。
代码块
Scala
for(i <- 1 to 3;j<- 1 to 4) println(s"i: $i,j: $j")
可以为每个生成器提供一个守卫,守卫是以if开头的Boolean表达式。
代码块
Scala
for(i <- 1 to 3;j<- 1 to 4 if i != j) println(s"i: $i,j: $j")
也可以在循环中定义变量,并在循环中使用变量。
代码块
Scala
for(i <- 1 to 3; num = 4 - i ;j<- num to 4 if i != j) println(s"i: $i,j: $j"