scala基础
介绍
Scalable Language
之所以说其是可伸缩的,是因为 scala 既体现了面向对象和函数式编程等不同语言范式,又融合了不同语言的新特性
The essence of Scala is the fusion of functional programming and object-oriented programming in a typed setting:
- Functions for the logic
- Objects for the modularity
As Martin Odersky has stated, “Scala was designed to show that a fusion of functional and object-oriented programming is possible and practical.”
官网:https://www.scala-lang.org/
Scala 语言是基于Java开发的,所以其编译后的文件也是字节码文件,并可以运行在JVM中
变量
在scala中有两种类型的变量
val创建一个不可变量(例如final在Java中)也就是常量,也可称为值valuevar创建一个可变变量
object Test {
def main(args: Array[String]): Unit = {
var s = "a"
s = "b"
val s1 = "a"
s1 = "b" //会报错
}
}
变量的类型如果能够通过变量值推断出来,那么可以省略类型声明,这里的省略,并不是不声明,而是由Scala编译器在编译时自动声明
object ScalaVariable {
def main(args: Array[String]): Unit = {
// 因为变量值为字符串,又因为Scala是静态类型语言,所以即使不声明类型
// Scala也能在编译时正确的判断出变量的类型,这体现了Scala语言的简洁特性。
var username = "zhangsan"
val userpswd = "000000"
}
}
Java语法中变量在使用前进行初始化就可以,但是Scala语法中是不允许的,必须显示进行初始化操作
与 Java含有基本类型不同,scala是完全面向对象的语言,所以不存在基本数据类型的概念,有的只是任意值对象类型(AnyVal)和任意引用对象类型(AnyRef)
Scala语言中没有三元运算符,不支持 a++ 语法,只能用a+=1
打印输出
字符串连接
object ScalaString {
def main(args: Array[String]): Unit = {
// 字符串连接
println("Hello " + name)
}
}
传值给字符串
object ScalaString {
def main(args: Array[String]): Unit = {
// 传值字符串(格式化字符串)
printf("name=%s\n", name)
}
}
插值字符串
object ScalaString {
def main(args: Array[String]): Unit = {
// 插值字符串
// 将变量值插入到字符串
println(s"name=${name}")
}
}
多行字符串
object ScalaString {
def main(args: Array[String]): Unit = {
// 多行格式化字符串
// 在封装JSON或SQL时比较常用
// | 默认顶格符
println(
s"""
| Hello
| ${name}
""".stripMargin)
}
}
循环中断
scala是完全面向对象的语言,所以无法使用break,continue关键字这样的方式来中断,或继续循环逻辑,
而是采用了函数式编程的方式代替了循环语法中的break和continue
object ScalaLoop {
def main(args: Array[String]): Unit = {
scala.util.control.Breaks.breakable {
for ( i <- 1 to 5 ) {
if ( i == 3 ) {
scala.util.control.Breaks.break
}
println(i)
}
}
}
}
函数式编程
scala编程语言将 函数式编程 和 面向对象编程 完美地融合在了一起
[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {
函数体
}
private def test( s : String ) : Unit = {
println(s)
}
scala中存在方法和函数两个不同的概念,二者在语义上的区别很小
scala方法是类的一部分,而函数是一个对象,也可以说类中定义的函数即是方法
类中的方法有重载和重写的概念而函数没有,函数可以嵌套声明而方法不可以
可变参数
函数中可变参数的写法如下,可变参数不能放在参数列表的前面,一般放在最后
object ScalaFunction {
def main(args: Array[String]): Unit = {
// Error
//def fun77(names:String*, name:String): Unit = {
//}
def fun777( name:String, names:String* ): Unit = {
println( name )
println( names )
}
}
}
函数至简原则
所谓的至简原则,其实就是Scala的作者为了开发人员能够大幅度提高开发效率
通过编译器的动态判定功能,帮助我们将函数声明中能简化的地方全部都进行了简化,也就是说将函数声明中那些能省的地方全部都省掉
所以这里的至简原则,简单来说就是:能省则省
高阶函数编程
所谓的高阶函数,其实就是将函数当成一个类型来使用,而不是当成特定的语法结构
面向对象编程
单例对象
所谓的单例对象,就是在程序运行过程中,指定类的对象只能创建一个,而不能创建多个,这样的对象可以由特殊的设计方式获得,也可以由语言本身设计得到,比如 object 伴生对象,对应java中的静态类
Scala语言是完全面向对象的语言,所以并没有静态的操作,但是为了能够和Java语言交互,就产生了一种特殊的对象来模拟静态类对象,该对象为单例对象
若单例对象名与类名一致,则称该单例对象是这个类的伴生对象,这个类的所有 “静态” 内容都可以放置在它的伴生对象中声明,然后通过伴生对象名称直接调用
如果类名和伴生对象名称保持一致,那么这个类称之为伴生类。Scala编译器可以通过伴生对象的apply方法创建伴生类对象。apply方法可以重载,并传递参数,且可由Scala编译器自动识别。所以在使用时,其实是可以省略的
特质
Scala 将多个类的相同特征从类中剥离出来,形成一个独立的语法结构,称之为 “特质”(特征),对应java中的接口
Scala中没有 interface 关键字,而是采用特殊的关键字 trait 来声明特质,如果一个类符合某一个特征(特质),那么就可以将这个特征(特质)“混入”到类中
这种混入的操作可以在声明类时使用,也可以在创建类对象时动态使用
基本语法
trait 特质名称
class 类名 extends 父类(特质1) with 特质2 with特质3
trait Operator {
}
trait DB{
}
class MySQL extends Operator with DB{
}
动态混入
object ScalaTrait{
def main(args: Array[String]): Unit = {
val mysql = new MySQL with Operator
mysql.insert()
}
}
trait Operator {
def insert(): Unit = {
println("insert data...")
}
}
class MySQL {
}
初始化叠加
object ScalaTrait{
def main(args: Array[String]): Unit = {
val mysql = new MySQL
}
}
trait Operator {
println("operator...")
}
trait DB {
println("db...")
}
class MySQL extends DB with Operator{
println("mysql...")
}
功能叠加
object ScalaTrait {
def main(args: Array[String]): Unit = {
val mysql: MySQL = new MySQL
mysql.operData()
}
}
trait Operate{
def operData():Unit={
println("操作数据。。")
}
}
trait DB extends Operate{
override def operData(): Unit = {
print("向数据库中。。")
super.operData()
}
}
trait Log extends Operate{
override def operData(): Unit = {
super.operData()
}
}
class MySQL extends DB with Log {
}
集合
Scala的集合有三大类:Seq、Set、Map,所有的集合都扩展自Iterable特质
对于几乎所有的集合类,Scala都同时提供了可变(scala.collection.mutable)和 不可变的版本(scala.collection.immutable )
这里的可变是指可以在适当的地方被更新或扩展,这意味着你可以修改,添加,移除一个集合的元素
而不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变,所以这里的不可变并不是变量本身的值不可变,而是变量指向的那个内存地址不可变
数组
-
不可变数组 :
Array -
可变数组 :
scala.collection.mutable.ArrayBuffer -
可变数组和不可变数组转换
import scala.collection.mutable import scala.collection.mutable.ArrayBuffer object ScalaCollection{ def main(args: Array[String]): Unit = { val buffer = ArrayBuffer(1,2,3,4) val array = Array(4,5,6,7) // 将不可变数组转换为可变数组 val buffer1: mutable.Buffer[Int] = array.toBuffer // 将可变数组转换为不可变数组 val array1: Array[Int] = buffer.toArray } }
Seq集合
-
不可变List :
List -
可变List :
scala.collection.mutable.ListBuffer -
可变集合和不可变集合转换
import scala.collection.mutable import scala.collection.mutable.ListBuffer object ScalaCollection{ def main(args: Array[String]): Unit = { val buffer = ListBuffer(1,2,3,4) val list = List(5,6,7,8) // 可变集合转变为不可变集合 val list1: List[Int] = buffer.toList // 不可变集合转变为可变集合 val buffer1: mutable.Buffer[Int] = list.toBuffer } }
Set集合
- 不可变Set :
Set - 可变Set :
import scala.collection.mutable.Set
Map集合
- 不可变Map :
Map - 可变Map :
scala.collection.mutable.Map
元组
在Scala语言中,我们可以将多个无关的数据元素封装为一个整体,这个整体我们称之为:元素组合,简称元组
队列
Scala也提供了队列(Queue)的数据结构 scala.collection.mutable.Queue,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue
并行
Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算
object ScalaCollection{
def main(args: Array[String]): Unit = {
val result1 = (0 to 100).map{x => Thread.currentThread.getName}
val result2 = (0 to 100).par.map{x => Thread.currentThread.getName}
println(result1)
println(result2)
}
}
模式匹配
Scala中的模式匹配类似于Java中的 switch 语法,但是scala从语法中补充了更多的功能,可以按照指定的规则对数据或对象进行匹配,所以更加强大
模式匹配语法中,采用 match 关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断
如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。如果不存在case _分支,那么会发生错误
object ScalaMatch{
def main(args: Array[String]): Unit = {
var a: Int = 10
var b: Int = 20
var operator: Char = 'd'
var result = operator match {
case '+' => a + b
case '-' => a - b
case '*' => a * b
case '/' => a / b
case _ => "illegal"
}
println(result)
}
}
样例类
-
样例类就是使用case关键字声明的类
-
样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如apply、unapply(即apply方法的逆过程,由对象到属性)、toString、equals、hashCode和copy
-
样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法
-
构造器中的每一个参数都为val,除非它被显式地声明为var(不建议这样做)
case class User(name: String, var age: Int)
object ScalaCaseClass {
def main(args: Array[String]): Unit = {
val user: User = User("zhangsan", 11)
val result = user match {
case User("zhangsan", 11) => "yes"
case _ => "no"
}
println(result)
}
}
应用场景
变量声明
object ScalaMatch {
def main(args: Array[String]): Unit = {
val (x, y) = (1, 2)
println(s"x=$x,y=$y")
val Array(first, second, _*) = Array(1, 7, 2, 9)
println(s"first=$first,second=$second")
val Person(name, age) = Person("zhangsan", 16)
println(s"name=$name,age=$age")
}
case class Person(name: String, age: Int)
}
循环匹配
object ScalaMatch {
def main(args: Array[String]): Unit = {
val map = Map("A" -> 1, "B" -> 0, "C" -> 3)
for ((k, v) <- map) { //直接将map中的k-v遍历出来
println(k + " -> " + v) //3个
}
println("----------------------")
//遍历value=0的 k-v ,如果v不是0,过滤
for ((k, 0) <- map) {
println(k + " --> " + 0) // B->0
}
println("----------------------")
//if v == 0 是一个过滤的条件
for ((k, v) <- map if v >= 1) {
println(k + " ---> " + v) // A->1 和 c->33
}
}
}
函数参数
object ScalaMatch {
def main(args: Array[String]): Unit = {
val list = List(
("a", 1), ("b", 2), ("c", 3)
)
val list1 = list.map {
case ( k, v ) => {
(k, v*2)
}
}
println(list1)
}
}
偏函数
所谓的偏函数,其实就是对集合中符合条件的数据进行处理的函数
偏函数也是函数的一种,通过偏函数我们可以方便的对输入参数做更精确的检查
List(1, 2, 3, 4, 5, 6, "test").collect { case x: Int => x + 1 }.foreach(println)
异常
Scala中的异常不区分所谓的 编译时异常和运行时异常,也无需显式抛出方法异常,所以Scala中没有throws关键字
object ScalaException {
def main(args: Array[String]): Unit = {
try {
var n= 10 / 0
} catch {
case ex: ArithmeticException=>{
// 发生算术异常
println("发生算术异常")
}
case ex: Exception=>{
// 对异常处理
println("发生了异常1")
}
} finally {
println("finally")
}
}
}
隐式转换
精度小的类型可以自动转换为精度大的类型,这个转换过程由编译器自动完成,这个转换操作我们称之为隐式转换
在其他的场合,隐式转换也起到了非常重要的作用。如Scala在程序编译错误时,可以通过隐式转换中类型转换机制尝试进行二次编译,将本身错误无法编译通过的代码通过类型转换后编译通过
慢慢地,这也形成了一种扩展功能的转换机制
隐式函数
object ScalaImplicit {
def main(args: Array[String]): Unit = {
implicit def transform( d : Double ): Int = {
d.toInt
}
var d : Double = 2.0
val i : Int = d
println(i)
}
}
隐式参数 & 隐式变量
object ScalaImplicit {
def main(args: Array[String]): Unit = {
def transform( implicit d : Double ) = {
d.toInt
}
implicit val dd : Double = 2.0
println(transform)
}
}
隐式类
隐式类非常强大,同样可以扩展类的功能,在集合的数据处理中,隐式类发挥了重要的作用
- 其所带的构造参数有且只能有一个
- 隐式类必须被定义在“类” 或 “伴生对象” 或 “包对象”里,即隐式类不能是顶级的
object ScalaImplicit {
def main(args: Array[String]): Unit = {
val emp = new Emp()
emp.insertUser()
}
class Emp {
}
implicit class User( emp : Emp) {
def insertUser(): Unit = {
println("insert user...")
}
}
}
隐式机制
所谓的隐式机制,就是一旦出现编译错误时,编译器会从哪些地方查找对应的隐式转换规则,其实最直接的方式就是直接导入
- 当前代码作用域
- 当前代码上级作用域
- 当前类所在的包对象
- 当前类(对象)的父类(父类)或特质(父特质)
泛型
泛型不可变
object ScalaGeneric {
def main(args: Array[String]): Unit = {
val test1 : Test[User] = new Test[User] // OK
val test2 : Test[User] = new Test[Parent] // Error
val test3 : Test[User] = new Test[SubUser] // Error
}
class Test[T] {
}
class Parent {
}
class User extends Parent{
}
class SubUser extends User {
}
}
泛型协变
object ScalaGeneric {
def main(args: Array[String]): Unit = {
val test1 : Test[User] = new Test[User] // OK
val test2 : Test[User] = new Test[Parent] // Error
val test3 : Test[User] = new Test[SubUser] // OK
}
class Test[+T] {
}
class Parent {
}
class User extends Parent{
}
class SubUser extends User {
}
}
泛型逆变
object ScalaGeneric {
def main(args: Array[String]): Unit = {
val test1 : Test[User] = new Test[User] // OK
val test2 : Test[User] = new Test[Parent] // OK
val test3 : Test[User] = new Test[SubUser] // Error
}
class Test[-T] {
}
class Parent {
}
class User extends Parent{
}
class SubUser extends User {
}
}
泛型边界
泛型上限
object ScalaGeneric {
def main(args: Array[String]): Unit = {
val parent : Parent = new Parent()
val user : User = new User()
val subuser : SubUser = new SubUser()
test[Parent](parent) // Error
test[User](user) // OK
test[SubUser](subuser) // OK
}
def test[A<:User]( a : A ): Unit = {
println(a)
}
class Parent {
}
class User extends Parent{
}
class SubUser extends User {
}
}
泛型下限
object ScalaGeneric {
def main(args: Array[String]): Unit = {
val parent : Parent = new Parent()
val user : User = new User()
val subuser : SubUser = new SubUser()
test[Parent](parent) // OK
test[User](user) // OK
test[SubUser](subuser) // Error
}
def test[A>:User]( a : A ): Unit = {
println(a)
}
class Parent {
}
class User extends Parent{
}
class SubUser extends User {
}
}
正则表达式
object ScalaRegex {
def main(args: Array[String]): Unit = {
// 构建正则表达式
val pattern = "Scala".r
val str = "Scala is Scalable Language"
// 匹配字符串 - 第一个
println(pattern findFirstIn str)
// 匹配字符串 - 所有
val iterator: Regex.MatchIterator = pattern findAllIn str
while ( iterator.hasNext ) {
println(iterator.next())
}
println("***************************")
// 匹配规则:大写,小写都可
val pattern1 = new Regex("(S|s)cala")
val str1 = "Scala is scalable Language"
println((pattern1 findAllIn str1).mkString(","))
}
}

浙公网安备 33010602011771号