1 scala语言特点
可拓展
- 面向对象
- 函数式编程
兼容JAVA
- 类库调用
- 互操作
语法简洁
- 代码行短
- 类型推断
- 抽象控制
静态类型化
- 可检验
- 安全重构
支持并发控制
- 强计算能力
- 自定义其他控制结构
2 scala与Java关系
- 都是基于JVM虚拟机运行的
Scala编译之后的文件也是.class,都要转换为字节码,然后运行在JVM虚拟机之上。
- Scala和Java相互调用
在Scala中可以直接调用Java的代码,同时在Java中也可以直接调用Scala的代码
- Java 8 VS Scala
- Java 8(lambda)没有出来之前,Java只是面向对象的一门语言,但是Java8出来以后,Java就是一个面向对象和面向函数的混合语言了。
- 首先我们要对Scala进行精确定位,从某种程度上讲,Scala并不是一个纯粹的面向函数的编程语言,有人认为Scala是一个带有闭包的静态面向对象语言),更准地说,Scala是面向函数与面向对象的混合。
- Scala设计的初衷是面向函数FP,而Java起家是面向对象OO,现在两者都是OO和FP的混合语言,是否可以这么认为:Scala =FP+OO,而Java = OO+ FP?
由于面向对象OO和面向函数FP两种范式是类似横坐标和纵坐标的两者不同坐标方向的思考方式,类似数据库和对象之间的不匹配阻抗关系,两者如果结合得不好恐怕就不会产生1+1>2的效果。
面向对象是最接近人类思维的方式,而面向函数是最接近计算机的思维方式。如果你想让计算机为人的业务建模服务,那么以OO为主;如果你希望让计算机能自己通过算法从大数据中自动建模,那么以FP为主。所以,Java可能还会在企业工程类软件中占主要市场,而Scala则会在科学计算大数据分析等领域抢占Java市场,比如Scala的Spark大有替代Java的Hadoop之趋势。
3 scala解释器
Scala解释器读到一个表达式,对它进行求值,将它打印出来,接着再继续读下一个表达式。这个过程被称做读取read–求值eval–打印print–循环loop,即:REPL。
从技术上讲,scala程序并不是一个解释器。实际发生的是,你输入的内容被快速地编译成字节码,然后这段字节码交由Java虚拟机执行。正因为如此,大多数scala程序员更倾向于将它称做 REPL。
4 scala变量的定义
scala的变量定义分为两种方式,分别需要使用关键字val和var。
- val
val a = 3
- var
var a = 3
val和var都可以用来定义变量,唯一的区别就在于,val定义的变量是不可变,而var定义的变量是可变的。不可变的量确实类似常量(被final修饰的变量),但不叫常量,只能叫不可变量的量。
在开发过程中,能使用val就使用val,var尽量不用,因为scala编程的特点,是在创建变量的时候可以省略数据类型,val有助于进行类型的推断。var在操作过程中不利于变量的类型推断。
一个完整的变量的定义如下:
val v:Int = 3
其中val为变量修饰符,v为变量名,Int为v的数据类型,其中需要将变量名和数据类型使用:连接,= 右侧为变量的值。
5 scala数据类型
scala支持的数据类型如下:
说明:
·scala拥有和java一样的数据类型,和java的数据类型的内存布局完全一致,精度也完全一致。需要说明一点的是Any和AnyRef,其中Any是对象的超类(运行时的一个概念,比如 val p = new Person() ,引用p指向的对象有一个父类Any),AnyRef是类的超类(class Person{}, 该类Person有一个隐含的超类AnyRef),实例/对象是类的具体化。
6 scala操作符说明
scala的操作符合java一模一样:略。
- 在scala调用一些方法或者函数的时候,如果方法或者函数是空参的,可以省略掉().
- 在scala中一行表示的结尾不像java需要使用";",scala可以省略
7 scala的流程控制结构
7.1 if表达式
scala中的if表达式,基本和java中的if表达式一模一样,唯一的区别就是scala中的if、if-else、if-elseif-else有返回值!
scala> val age = 18
age: Int = 18
scala> if(age > 16) "adult" else "child"
res17: String = adult
scala> val ret = if(age > 16) "adult" else "child"
ret: String = adult
scala> println("ret = " + ret)
ret = adult
scala> var result = ""
result: String = ""
scala> if(age > 16) result = "adult" else result = "child"
scala> println("result= " + result)
result= adult
scala> if(age > 16) "adult" else 123
res21: Any = adult
记住:scala中任意的表达式,都有返回值。
如果else丢失了
if(x>0) 1
那么有可能if语句没有输出值,但是在Scala中,每个表达式都有值,这个问题的解决方案是引入一个Unit类,写作(),不带else语句的if语句等同于if(x>0) 1 else ()
scala的返回值可以省略return关键字,表达式的最后一句话,作为表达式的返回值返回。return关键字通常使用在函数中进行逻辑的终止,比如循环。
var f = 3
var n = 10
var m = 1
val d = if(n < 18){f = f + n ; m = m +n ; f+m}
===> d=24
注意:前面提到过,scala中的语句终止就是换行,也就是一行一个语句,此时便可以省略";",但是当一行有多条语句的时候,就应该使用";"分隔。在表达式块中同样可以使用换行作为一条语句的分隔。
如果if循环体{}中只有一条语句,是可以省略{},但是如果大家查看过阿里巴巴编程规范中话,其建议哪怕只有一条语句也写上{},会显得结构很清晰。
7.2 while循环
object whileLoop {
def main(args: Array[String]): Unit = {
var sum = 0
var n = 1
while(n <= 10) {
sum += n
//++/--自增/自减运算符在scala中不支持,因为已经被scala集合的对应函数所占据了
// n++
n += 1
}
println("sum = " + sum)
}
}
注意:error: value ++/-- is not a member of Int
scala中不能直接对一个变量执行自增/减,++/–是scala集合的一个函数。
7.3 do while循环
object doWhileLoop {
def main(args: Array[String]): Unit = {
var sum = 0
var n = 1
do {
sum += n
n += 1
} while (n <= 10)
println("sum = " + sum)
}
}
7.4 循环练习
登录用户名密码的游戏:三次机会,从控制台输入用户名密码,如果成功登录,返回登录成功,失败,则反馈错误信息!
object whileLoopTest {
def main(args: Array[String]): Unit = {
//从控制台输入使用readLine()已经过时
// readLine()//StdIn.readLine
val user = "goodera"
val passwd = "123456"
var count = 3
while(count > 0) {
count -= 1
val username = StdIn.readLine("请输入您的用户名:")
val pwd = StdIn.readLine("请输入您的密码:")
if (user == username && passwd == pwd) {
println("欢迎" + username + "登录xxx官网~")
count = -1
//return
} else {
println("用户名或密码有误,请重试,还有" + count + "次机会~")
}
}
}
}
7.5 循环的终止
在java中终止循环有关键字,continue,break,return,但是在scala中没有前两者continue和break。该如何终止循环呢?
scala中有三种方式来结束循环:
- 使用return语句来控制循环结束
- 使用循环结束的条件来进行控制,比如上例中的count >= 0
- 还可以使用breakable函数体来进行控制
object whileLoopTest {
def main(args: Array[String]): Unit = {
val user = "goodera"
val passwd = "123456"
var count = 3
breakable {
while(count > 0) {
count -= 1
val username = StdIn.readLine("请输入您的用户名:")
val pwd = StdIn.readLine("请输入您的密码:")
if (user == username && passwd == pwd) {
println("欢迎" + username + "登录xxx官网~")
break
} else {
println("用户名或密码有误,请重试,还有" + count + "次机会~")
}
}
}
}
}
7.6 for循环
在java中有2中写法,普通的for循环for(变量;条件;自增或自减){循环体}和增强型for(类型 变量 : 集合) {}。
scala中并没有像java中普通for循环的语法结构,更像是高级for循环。
for (变量 <- 集合) {
}
将上述的while循环使用for循环改写:
/*
java的for循环
for(int a = 0初始化①; a < 10条件判断②; a++变量改变③) {
//循环体
业务逻辑④
}
1->2->4->3->2->4->3...
高级for循环foreach
for(类型 变量 : 集合) {
xxxx
}
scala中没有像java中的第一种for循环,scala中的for循环,有点类似java中的高级for循环,
结构如下:
for(变量 <- 集合) {
}
*/
object forLoop {
def main(args: Array[String]): Unit = {
/*
将前面的while循环案例适用for循环实现
scala中生成一个集合可以使用整型变量 to/until 数字
会生成一个返回
to: 1 to 5/1.to(5) 包含
scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)
until: 1 until 5/1.until(5) 不包含
scala.collection.immutable.Range = Range(1, 2, 3, 4)
*/
val range = 1.to(10)
var sum = 0
for(n <- range) {
sum += n
}
println("sum = " + sum)
}
}
val range = 1.to(10)
var sum = 0
for(n <- range reverse) {
println("n=" + n)
}
说明:添加reverse主要就是向进行循环的反转
7.7 循环的嵌套
/*
循环的嵌套
打印矩阵
*****
*****
*****
3行 * 5列
循环的嵌套中:外循环控制行,内循环控制每一行对应的列
*/
object loopNest {
def main(args: Array[String]): Unit = {
for(i <- 1 to 3) {
for(j <- 1 to 5) {
print("*")
}
println
}
println("----------打印一个三角形-------------")
for(i <- 1 to 5) {
for(j <- 1 to 5) {
if(j <= i)
print("*")
}
println
}
println("----------改写打印一个三角形-------------")
for(i <- 1 to 5) {
for(j <- 1 to i) {
print("*")
}
println
}
println("----------改写打印一个三角形-------------")
for(i <- 1 to 5) {
for(j <- i to 5) {
print("*")
}
println
}
println("----------scala for嵌套写法-------------")
for(i <- 1 to 5; j <- 1 to i) {
print("*")
if(i == j) {
println
}
}
println("----------scala for嵌套写法-------------")
for(i <- 1 to 5; j <- 1 to 5; if j <= i) {
print("*")
if(i == j) {
println
}
}
}
}
scala打印9*9乘法口诀表:
object multipTable {
def main(args: Array[String]): Unit = {
for(i <- 1 to 9; j <- 1 to 9; if j <= i) {
// print(j + "*" + i + "=" + (i * j) + "\t")
print(s"${j}*${i}=${i * j}\t")
if(i == j) {
println
}
}
}
}
8 scala异常控制
scala的异常体系,在很大程度上沿用java的异常体系的,只不过在书写结构上略有差异。
/**
* scala异常控制
*/
object exceptionDemo {
def main(args: Array[String]): Unit = {
try {
// var i = 1 / 0
//lazy 懒加载 或者延迟加载 被lazy所修饰的变量,之后再第一次被调用的时候才会进行初始化
lazy val num = Integer.valueOf("abcd")
// println(num)
// val file = new FileInputStream("abedefg")
} catch {
case e: ArithmeticException => {
println(e.getMessage)
}
case e1: NumberFormatException => {
// println(e1.getMessage)
e1.printStackTrace()
}
case _:Exception => {//_下划线代表上述没有匹配到的其他的异常
println("文件找不到")
// throw new RuntimeException("RuntimeException")
}
}
}
}
上述代码,在执行过程中出现异常:
java.lang.ArithmeticException: / by zero
在java中学习了两种异常的处理方式:throws和try-catch。scala中throws和java中的一模一样,将异常转交给调用者进行处理。try-catch则意味着自己要进行处理,但是编写的方式和java不一样。
case e: ArithmeticException => {
println(e.getMessage)
}
说明:上面的案例中,更进一步的学习了一个关键字lazy(懒加载),被lazy所修饰的变量,只有当第一次被使用的时候才会进行初始化,没有使用之前只是记录了存在,检查语法结构是否正确。可以节省一定的资源空间。