环境配置
概述
Scala将面向对象和函数式编程结合成一种简洁的高级语言。
语言特点如下:
(1)Scala和Java一样属于JVM语言,使用时都需要先编译为class字节码文件,并且Scala能够直接调用Java的类库。
(2)Scala支持两种编程范式面向对象和函数式编程。
(3)Scala语言更加简洁高效;语法能够化简,函数式编程的思想使代码结构简洁。
(4)作者马丁·奥德斯基设计Scala借鉴了Java的设计思想,同时优秀的设计也推动了Java语言的发展。
环境搭建
(1)首先确保JDK1.8安装成功
(2)下载对应的Scala安装文件scala-2.12.10.zip
(3)解压scala-2.12.10.zip,解压到任意没有中文的路径,例如D:\Tools
(4)配置Scala的环境变量 : SCALA_HOME 为安装路径;在path添加值%SCALA_HOME%\bin
在终端中输入scala可以使用相关语法。
idea中的hello world案例
创建一个项目。创建过程中选择scala语言会默认提示添加相关插件,提示需要重启。
重启后重新创建即可成功。
创建测试代码(我这里是默认生成的,和idea版本有关)
1 2 3 4 5
| object Main { def main(args: Array[String]): Unit = { println("Hello world!") } }
|
如果是maven项目,先创建一个java的maven项目,然后右键项目添加scala支持即可(Add Framework Support)。
变量和数据类型
注释
Scala注释使用和Java完全一样。
变量和常量
常量:在程序执行的过程中,其值不会被改变的变量。
1 2
| var 变量名 [: 变量类型] = 初始值 var i:Int = 10 val 常量名 [: 常量类型] = 初始值 val j:Int = 20
|
注意:能用常量的地方不用变量。
1 2 3 4 5
| 声明变量时,类型可以省略,编译器自动推导,即类型推导。 类型确定后,就不能修改,说明Scala是强数据类型语言。 变量声明时,必须要有初始值。 在声明/定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改。 var修饰的对象引用可以改变,val修饰的对象则不可改变,但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package org.example
object Test01 { def main(args: Array[String]): Unit = { // 声明变量和常量 val a: Int = 10 var b: Int = 20
// 常量值无法修改 // a = 20 b = 30 // (1)声明变量时,类型可以省略,编译器自动推导,即类型推导 val c = 30 // (2)类型确定后,就不能修改,说明Scala是强数据类型语言。
// b = "30"
// (3)变量声明时,必须要有初始值 val d: Int = 0
// var d1:Int = _
val test02 = new Test02() println(test02.i)
// (4)var修饰的对象引用可以改变,val修饰的对象则不可改变, // 但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等) val person0 = new Person() var person1 = new Person()
// 引用数据类型的常量和变量能否替换成别的对象 // var 可以修改引用数据类型的地址值 val不行 person1 = new Person()
// 引用数据类型中的属性值能否发生变化 取决于内部的属性在定义的时候是var还是val // person0.name = "lisi" person0.age = 11
}
}
class Test02 {
// scala中类的属性 如果是var变量也能使用默认值 但是必须要有等号 var i: Int = _ }
class Person { val name: String = "zhangsan" var age: Int = 10 }
|
标识符的命名规范
Scala对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可以起名字的地方都叫标识符。
1)命名规则
Scala中的标识符声明,基本和Java是一致的,但是细节上会有所变化(java可支持中文字母即汉字,但是scala显然不可以),有以下三种规则:
(1)以字母或者下划线开头,后接字母、数字、下划线
(2)以操作符开头,且只包含操作符(+ - * / # !等)
(3)用反引号....
包括的任意字符串,即使是Scala关键字(39个)也可以
注意:正常使用不能只遵守规则,必须按照规范来写,即使用大小驼峰命名法。
字符串输出
基本语法
(1)字符串,通过+号连接。
(2)重复字符串拼接。
(3)printf用法:字符串,通过%传值。
(4)字符串模板(插值字符串):通过$获取变量值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| object Test03 { def main(args: Array[String]): Unit = { // (1)字符串,通过+号连接 println("hello" + "world")
// (2)重复字符串拼接 println("linhailinhai" * 5)
// (3)printf用法:字符串,通过%传值。 printf("name: %s age: %d\n", "linhai", 8)
// (4)字符串模板(插值字符串):通过$获取变量值 val name = "linhai" val age = 8
val s1 = s"name: $name,age:${age}" println(s1)
val s2 = s"name: ${name + 1},age:${age + 2}" println(s2)
// (5)长字符串 原始字符串 println("我" + "是" + "一首" + "诗")
//多行字符串,在Scala中,利用三个双引号包围多行字符串就可以实现。 // 输入的内容,带有空格、\t之类,导致每一行的开始位置不能整洁对齐。 //应用scala的stripMargin方法,在scala中stripMargin默认是“|”作为连接符, // 在多行换行的行头前面加一个“|”符号即可。 println( """我 |是 |一首 |诗 |""".stripMargin)
println(""" |select id, | age |from user_info |""".stripMargin)
println(s""" |${name} |${age} |""".stripMargin) } }
|
数据类型
1 2 3 4 5 6 7 8 9
| Any: 所有类的父类 AnyVal: 值类型 Byte、Short、Int、Float、Double、Long、Char、Boolean Unit: 相当于java的void,有一个实例() Stringops: 对java字符串扩展的统称 AnyRef: 引用类型 String、java数组\集合\class、scala数组\集合\class Null: 是所有引用类型的子类,有一个实例null,null一般用于给引用类型赋予初始值,在赋予初始值的时候必须指定变量类型。 Nothing: 所有类型的子类
|
值类型
和java基本数据类型相似,只是这里是对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| // 整数类型 val i1 = 1
val l = 1L
val b1: Byte = 2 // val b0: Byte = 128
//编译器对于常量值的计算 能够直接使用结果进行编译 // 但是如果是变量值 编译器是不知道变量的值的 所以判断不能将大类型的值赋值给小的类型 val i2 = 1 // val b3: Byte = i2 + 1 // println(b3)
// Scala程序中变量常声明为Int型,除非不足以表示大数,才使用Long val l1 = 2200000000L
// 浮点数介绍 // 默认使用double val d: Double = 3.14
// 如果使用float 在末尾添加f val fl = 3.14f
// 浮点数计算有误差 println(0.1 / 3.3)
// 字符常量是用单引号 ' ' 括起来的单个字符。 val c1: Char = 'a' val c2: Char = 65535
// \t :一个制表位,实现对齐的功能 val c3: Char = '\t'
// \n :换行符 val c4: Char = '\n' println(c3 + 0) println(c4 + 0)
// \\ :表示\ val c5: Char = '\\' println(c5 + 0)
// \" :表示" val c6: Char = '\"' println(c6 + 0)
val bo1: Boolean = true val bo2: Boolean = false
|
Unit类型、Null类型和Nothing类型
Unit 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。
Null null , Null 类型只有一个实例值null
Nothing Nothing类型在Scala的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性)
Unit类型用来标识过程,也就是没有明确返回值的函数。
由此可见,Unit类似于Java里的void。Unit只有一个实例——( ),这个实例也没有实质意义。
1 2 3 4 5 6 7 8 9 10 11 12
| // unit val unit1: Unit = { 10 println("1") } println(unit1)
// 如果标记对象的类型是unit的话 后面有返回值也没法接收 // unit虽然是数值类型 但是可以接收引用数据类型 因为都是表示不接收返回值 val i3: Unit = "aa" println(i3)
|
Null类只有一个实例对象,Null类似于Java中的null引用。Null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| // scala当中使用的字符串就是java中的string val aa: String = "aa"
// null var aa1: String = "aa"
aa1 = "bb" aa1 = null if (aa1 != null) { val strings: Array[String] = aa1.split(",") }
// 值类型不能等于null,idea不会识别报错 编译器会报错 var i4 = 10 // i4 = null
|
Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。
类型转换
数值类型自动转换
与java规则一致。
自动提升原则:
有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。
把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
强制类型转换
自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。
1 2
| Java : int num = (int)2.5 Scala : var num : Int = 2.7.toInt
|
1 2 3 4 5 6 7 8
| // 强制类型转换 val d1 = 2.999 // 将数据由高精度转换为低精度,就需要使用到强制转换 println((d1 + 0.5).toInt)
// 强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级 println((10 * 3.5 + 6 * 1.5).toInt)
|
数值类型和String类型间转换
基本类型转String类型(语法:将基本类型的值+”” 即可)。
String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // 基本类型转String类型(语法:将基本类型的值+"" 即可) val string: String = 10.0.toString println(string)
val str: String = 1 + ""
// String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort) val double: Double = "3.14".toDouble
println(double + 1) println(double.toInt)
// 不能直接将小数类型的字符串转换为整数 需要先转换为double再转换int // println("3.14".toInt)
// 标记为f的float数能够识别 println("12.6f".toFloat)
|
运算符
Scala运算符的使用和Java运算符的使用基本相同,只有个别细节上不同。
1 2
| Scala:==更加类似于Java中的equals Scala中没有++、--操作符,可以通过+=、-=来实现同样的效果
|
在Scala中其实是没有运算符的,所有运算符都是方法。
当调用对象的方法时,点.可以省略
如果函数参数只有一个,或者没有参数,()可以省略
1 2 3 4 5 6 7 8 9 10 11 12
| // 标准的加法运算 val i:Int = 1.+(1)
// (1)当调用对象的方法时,.可以省略 val j:Int = 1 + (1)
// (2)如果函数参数只有一个,或者没有参数,()可以省略 val k:Int = 1 + 1
println(1.toString()) println(1 toString()) println(1 toString)
|
流程控制
分支控制if-else
可以向java中使用一样
1 2 3 4 5 6 7 8 9 10
| println("input age") var age = StdIn.readInt()
if (age < 18){ println("童年") }else if(age>=18 && age<60){ println("中年") }else{ println("老年") }
|
ifelse有返回值
Scala中if else表达式其实是有返回值的,具体返回值取决于满足条件的代码体的最后一行内容。
1 2 3 4 5 6 7 8 9 10 11 12
| println("input age") var age = StdIn.readInt()
val res :String = if (age < 18){ "童年" }else if(age>=18 && age<60){ "中年" }else{ "老年" }
println(res)
|
Scala中返回值类型不一致,取它们共同的祖先类型
1 2 3 4 5 6 7 8 9 10 11 12
| println("input age") var age = StdIn.readInt()
val res:Any = if (age < 18){ "童年" }else if(age>=18 && age<60){ "中年" }else{ 100 }
println(res)
|
Java中的三元运算符可以用if else实现.
1 2 3 4 5
| println("input age") var age = StdIn.readInt() val res:Any = if (age < 18) "童年" else "成年"
println(res)
|
For循环控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| // scala中的for循环基础语法 for (i <- 0 to 5) { println(i) }
for (i <- 0 until 5) { println(i) }
// for循环的本质 // to是整数的方法 返回结果是一个集合 // 使用变量i 循环遍历一遍 后面集合的内容 val inclusive: Range.Inclusive = 0.to(5) println(inclusive.toList)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| // 循环守卫 for (i <- 0 to 10) { if (i > 5) { println(i) } }
for (i <- 0 to 10 if i > 5) { println(i) }
// 循环返回值 val ints = for (i <- 0 to 3) yield { 10 } println(ints)
|
While和do..While循环控制
和java一致。
循环中断
采用Scala自带的函数,退出循环
1 2 3 4 5 6 7 8
| Breaks.breakable( for (elem <- 1 to 10) { println(elem) if (elem == 5) Breaks.break() } )
println("正常结束循环")
|
对break进行省略
1 2 3 4 5 6 7 8 9 10
| import scala.util.control.Breaks.{break, breakable}
breakable { for (elem <- 1 to 10) { println(elem) if (elem == 5) break } } println("正常结束循环")
|
猜数字