Scala从入门到精通

1 初识 Scala

1.1 Scala 概述

Scala 是一门多范式的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。

Scala 是运行于 Java 平台(Java 虚拟机)上,并兼容现有的 Java 程序。

Scala 的编译模型(独立编译,动态类加载)与 Java 和 C# 一样,所有 Scala 代码可以调用 Java 类库(对于 .NET 实现则可调用 ,NET 类库)。

2 Scala 入门

2.1 var 和 val 的区别

var:变量,可以修改值

val:值,不能修改值

2.2 lazy 在 Scala 中的应用

scala> lazy val age = 10
age: Int = <lazy>

scala> age
res0: Int = 10
//返回一个lazy,只有真正执行时才会赋值

scala> val age = 10
age: Int = 10

2.3 基本数据类型

Byte/Char

Short/Int/Long/Float/Double

Boolean

3 Scala 函数

3.1函数的定义和使用

def 方法名(参数名:参数类型) : 返回值类型 = {

​ // 括号内的叫做方法体

​ // 方法体内的最后一行为返回值,不需要使用 return

}

方法中只有一行代码,可以省略 {}

方法中没有参数,调用时可以省略 ()

3.2 默认参数

def 方法名(参数名:参数类型 = 值) : 返回值类型 = {

}

在函数定义时,允许指定参数的默认值

3.3 命名参数

def 方法名(参数名:参数类型) : 返回值类型 = {

}

在函数调用时,允许指定参数的属性名进行传值

3.4 可变参数

def 方法名(参数名:参数类型 *) : 返回值类型 = {

}

在函数调用时,允许传递多个属性值

3.5 条件表达式

if (command) true else false

3.6 循环表达式

to 左闭右闭

scala> for (i <- 1 to 10) {}

Range 左闭右开

scala> for (i <- Range(1, 10)) {}

until 左闭右开

scala> for (i <- 1.until(10)) {}

循环守卫

scala> for (i <- 1 to 10 if i % 2 == 0) {}

循环遍历

scala> val courses = Array("Hadoop", "Spark SQL", "Spark Streaming", "Strom", "Scala")
courses: Array[String] = Array(Hadoop, Spark SQL, Spark Streaming, Strom, Scala)

scala> courses.foreach(course => println(course))
Hadoop
Spark SQL
Spark Streaming
Strom
Scala

4 Scala 对象

4.1 面向对象概述

封装:属性、方法封装到类中

继承:父类和子类之间的关系,子类继承父类的属性和方法

多态:父类引用指向子类对象

4.2 类的定义和使用

class People {

    // 定义属性
    var name : String = _
    val age: Int = 10

    // 只能在class中使用
    private [this] val gender = "male"

    def printInfo(): Unit = {
        println("gender: " + gender)
    }
    def eat(): String = {
        name + "eat..."
    }

    def watchFootball(teamName : String): Unit = {
        println(name + "is watching match of " + teamName)
    }
}

4.3 主构造器和辅助构造器

// 主构造器
class Person(val name:String, val age:Int) {
    println("Person Constructor enter...")

    var school = "ustc"

    var gender:String = _

    // 辅助构造器
    def this(name:String,age: Int, gender:String) {
        // 辅助构造器的第一行代码必须调用主构造器或辅助构造器
        this(name,age)
        this.gender = gender
    }

    println("Person Constructor leave...")
}

4.4 继承

// 子类继承父类时父类已有的属性直接继承,没有的属性必须加var或val
class Student(name: String, age: Int, var major: String) extends Person(name, age) {
    println("Student Constructor enter...")
    println("Student Constructor leave...")
}

4.5 重写

// 子类继承父类时父类已有的属性直接继承,没有的属性必须加var或val
class Student(name: String, age: Int, var major: String) extends Person(name, age) {
    println("Student Constructor enter...")

    // 重写父类继承的属性或方法时,必须加override关键字
    override var school = "peking"
    override def toString = "Student: override def toString"

    println("Student Constructor leave...")
}

4.6 抽象类

/**
 * 类的一个或者多个方法没有完整的实现,只有定义
 */
abstract class Person2 {

    def speak

    var name: String
    val age: Int
}

class Student2 extends Person2 {
    override def speak: Unit = {
        println("speak")
    }

    override var name: String = _
    override val age: Int = 10
}

4.7 伴生类和伴生对象

如果有一个 class,还有一个同名的 object,那么就称 object 是 class 的伴生对象 ,class 是 object 的伴生类

4.8 apply 方法

object ApplyApp {
    def main(args: Array[String]): Unit = {
        for (i <- 1 to 10) {
            ApplyTest.incr
        }
        // object是一个单例对象
        println(ApplyTest.count)
        // 类名() => Object.apply
        // 对象() => Class.apply
        val apply1 = ApplyTest()
        val apply2 = new ApplyTest()
        apply2()
    }
}

class ApplyTest {
    def apply() = {
        println("Class ApplyTest apply...")
    }
}

object ApplyTest {

    var count = 0

    def incr = {
        count = count + 1
    }

    // 最佳实践:在Object的apply方法中new Class
    def apply() = {
        println("Object ApplyTest apply...")
    }

}

4.9 case class

object CaseClassApp {
    def main(args: Array[String]): Unit = {
        println(Dog("大黄").name)
    }
}

//case class不用new,通常用于模式匹配
case class Dog(name: String) {

}

4.10 trait

在 trait 中方法是抽象方法,不给出具体的方法体

在 Scala 中无论是继承还是实现都使用 extends,必须实现其中的抽象方法,实现时不需要使用 override 关键字,同时 Scala 同 Java 一样,不支持多继承类,但是支持多继承接口,使用 with 关键字

class xxx extends xxxclass {}
class xxx extends xxxtarit {}
class xxx extends xxxclass with xxxtrait {}
class xxx extends xxxtrait with xxxtarit1 ... {}

5 Scala 集合

5.1 定长数组

scala> val a = new Array[String](5)
a: Array[String] = Array(null, null, null, null, null)

scala> println(a.mkString(","))
null,null,null,null,null

scala> val b = Array("Hadoop", "Spark", "Storm")
b: Array[String] = Array(Hadoop, Spark, Storm)

scala> println(b.mkString(","))
Hadoop,Spark,Storm

scala> val c = Array(2, 3, 4, 5, 6, 7, 8, 9)
c: Array[Int] = Array(2, 3, 4, 5, 6, 7, 8, 9)

scala> println(c.mkString(","))
2,3,4,5,6,7,8,9

5.2 变长数组

var d = scala.collection.mutable.ArrayBuffer[Int]()
// 添加元素
d += 1
d += (2, 3, 4, 5)
// 添加数组
d ++= c
// 在指定位置添加元素
d.insert(0, 0)
// 删除指定位置的元素
d.remove(1)
// 从指定位置开始删除多少个元素
d.remove(0, 3)
// 从末尾删除多少个元素
d.trimEnd(2)
// 转换成不可变数组
d.toArray

5.3 List

// 不可变列表
val l = List(1, 2, 3, 4, 5)
// Nil表示一个空的集合
val l2 = 1 :: Nil
// 将1作为head,将后面的作为tail
val l3 = 1 :: 2 :: l :: Nil
val l4 = 1 :: 2 :: l :: 4 :: Nil
// 可变列表
val l5 = scala.collection.mutable.ListBuffer[Int]()
l5 += 1
l5 += (2, 3, 4, 5)
l5 ++= List(6, 7, 8, 9)
l5 -= 1
l5 -= (1,2,3)
l5 --= List(2, 3, 4, 5)
l5.toList

5.4 Set

和 List 类似,区别是 Set 无序且不重复

5.5 Map

// 不可变Map
val a = Map("PK" -> 18, "zhangsan" -> 30)
// 可变Map
var b = scala.collection.mutable.Map("PK" -> 18, "zhangsan" -> 30)
// 空Map
var c = scala.collection.mutable.HashMap[String, Int]()
println(b.get("lisi"))
println(b.get("lisi").get)
println(b.getOrElse("lisi", "default"))

5.7 Option&Some&None

Option[T] 是一个类型为 T 的可选值的容器:

如果值存在, Option[T] 就是一个 Some[T] ;

如果不存在, Option[T] 就是对象 None 。

5.8 Tuple

var a = (1,2,3,4,5)
for (i <- 0 until (a.productArity)) {
println(a.productElement(i))
}
// 通过元祖._索引取值,索引从1开始
println(a._1)

6 Scala 模式匹配

6.1 最基础的模式匹配

val names = Array("Dennis Ritchie", "James Gosling", "Brendan Eich", "John McCarthy")
val name = names(Random.nextInt(names.length))
name match {
    case "Dennis Ritchie" => println("names[0]")
    case "James Gosling" => println("names[1]")
    case "Brendan Eich" => println("names[2]")
    case _ => println("names[3]")
}

6.2 加条件进行匹配

def judgeGrade(name: String, grade: String): Unit = {
    grade match {
        case "A" => println("Excellent...")
        case "B" => println("Good...")
        case "C" => println("Just so so...")
        case _ if (name == "PK") => println(name + ", you need work hard...")
        case _ => println("You need work hard...")
    }
}

6.3 Array 模式匹配

def greeting(array: Array[String]): Unit = {
    array match {
        case Array("zhangsan") => println("Hi:zhangsan")
        case Array(x,y) => println("Hi:" + x + "," + y)
        case Array("zhangsan", _*) => println("Hi:zhangsan and other")
        case _ => println("Hi:...")
    }
}

6.4 List 模式匹配

def greeting(list: List[String]): Unit = {
    list match {
        case "zhangsan" :: Nil => println("Hi:zhangsan")
        case x :: y :: Nil => println("Hi:" + x + "," + y)
        case "zhangsan" :: tail => println("Hi:zhangsan and other")
        case _ => println("Hi:...")
    }
}

6.5 类型匹配

def matchType(obj: Any): Unit = {
    obj match {
        case x: Int => println("Int")
        case s: String => println("String")
        case m: Map[_, _] => println("Map")
        case _ => println("other")
    }
}

6.6 Scala 异常处理

try {
    var i = 10 / 0
    println(i)
} catch {
    case e: ArithmeticException => println("除数不能为0")
    case e: Exception => println(e.getMessage)

} finally {
    // 释放资源
}

6.7 case class 模式匹配

class Person

case class CTO(name:String, floor:String) extends Person

case class Employee(name:String, floor:String) extends Person

case class Other(name:String, floor:String) extends Person

def caseclassMatch(person: Person): Unit = {
    person match {
        case CTO(name,floor) => println("CTO name is: " + name + ", floor is: " + floor)
        case Employee(name,floor) => println("Employee name is: " + name + ", floor is: " + floor)
        case _ => println("Other")
    }
}

6.8 Some None 模式匹配

def getGrade(name:String): Unit = {
    val grade = map.get("name")

    grade match {
        case Some(grade) => println("you grade is: " + grade)
        case None => println("None")
    }
}

7 Scala 函数高级操作

7.1 字符串高级操作

插值表达式

scala> println(s"Hello $name")
Hello PK

多行字符串

"""
|xxx
|xxx
|xxx
|""".stripMargin

7.2 匿名函数

(参数名 : 参数类型) => {

​ // 方法体

}

7.3 currying 函数

将原来接收两个参数的一个函数,转换成 2 个

def (参数名 : 参数类型) (参数名 : 参数类型) : 返回值类型 = {

​ // 方法体

}

方法名(值)(值)

7.4 高阶函数

Map

map 操作是针对集合的典型变换操作,它将某个函数应用到集合中的每个元素,并产生一个结果集合

scala> val books = List("Hadoop", "Hive", "HDFS")
books: List[String] = List(Hadoop, Hive, HDFS)
scala> books.map(s => s.toUpperCase)
res0: List[String] = List(HADOOP, HIVE, HDFS)   

Filter

filter 操作是遍历一个集合并从中获取满足指定条件的元素组成一个新的集合

val university = Map("XMU" -> "Xiamen University", "THU" -> "Tsinghua University","PKU"->"Peking University","XMUT"->"Xiamen University of Technology")

然后我们采用 filter 操作过滤得到那些学校名称中包含 Xiamen 的元素:

val universityOfXiamen = university filter {kv => kv._2 contains "Xiamen"}

FlatMap

flatMap 是 map 的一种扩展,在 flatMap 中,我们会传入一个函数,该函数对每个输入都会返回一个集合(而不是一个元素),然后,flatMap 把生成的多个集合拍扁成为一个集合

scala> val books = List("Hadoop","Hive","HDFS")
books: List[String] = List(Hadoop, Hive, HDFS)
scala> books flatMap (s => s.toList)
res0: List[Char] = List(H, a, o, o, p, H, i, v, e, H, D, F, S)

Reduce

reduce 归纳、简化的意思,把容器中的元素作参数传给里面的二元匿名函数

reduce 包含 reduceLeft 和 reduceRight 两种操作,前者从集合的头部开始操作,后者从集合的尾部开始操作

scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)
scala> list.reduceLeft(_ + _)
res21: Int = 15
scala> list.reduceRight(_ + _)
res22: Int = 15

Fold

折叠操作和归约操作比较类似,fold 操作需要从一个初始的种子值开始,并以该值作为上下文,处理集合中的每个元素

scala> val list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)
 
scala> list.fold(10)(_*_)
res0: Int = 1200

可以看出,fold 函数实现了对 list 中所有元素的累乘操作,fold 函数需要两个参数,一个参数是初始种子值,这里是 10,另一个参数是用于计算结果的累计函数,这里是累乘。

执行 list.fold(10)(_*_) 时,首先把初始值拿去和 list 中的第一个值 1 做乘法操作,得到累乘值 10,然后再拿这个累乘值 10 去和 list 中的第 2 个值 2 做乘法操作,得到累乘值 20,依此类推,一直得到最终的累乘结果 1200

fold 有两个变体:

  • foldLeft(),第一个参数为累计值,集合遍历的方向是从左到右
  • foldRight(),第二个参数为累计值,集合遍历的方向是从右到左,对于fold()自身而言,遍历的顺序是未定义的,不过,一般都是从左到右遍历

7.5 偏函数

8 Scala 隐式转换

8.1 隐式转换概述

为一个已存在的类添加一个新的方法的过程

8.2 隐式转换实战

object ImplicitApp {
    def main(args: Array[String]): Unit = {
        // 定义格式转换函数
        implicit def man2superMan(man:Man) = new SuperMan(man.name)

        val man = new Man("PK")
        man.fly()

        implicit def file2RichFile(file: File) = new RichFile(file)
        
        val file = new File("")
        file.read()
    }
}

class Man(val name:String) {
    def eat(): Unit = {
        println(s"name [ $name ] eat ....")
    }
}

class SuperMan(val name:String) {
    def fly(): Unit = {
        println(s"name [ $name ] fly ....")
    }
}

class RichFile(val file:File) {
    def read() = {
        scala.io.Source.fromFile(file.getPath).mkString
    }
}

8.3 隐式转换切面封装

object ImplicitAspect {
    
    implicit def man2superMan(man: Man) = new SuperMan(man.name)

    implicit def file2RichFile(file: File) = new RichFile(file)

}

然后在其他需要隐式转换的类中导入

8.4 隐式类

object ImplicitClassApp {
    def main(args: Array[String]): Unit = {
        println(1.add(3))
    }

    // 表示将所有的int类型增加了add方法
    implicit class Cal(x: Int) {
        def add(a: Int) = a + x
    }

}

9 Scala 操作外部数据

9.1 Scala 读取文件及网络数据

object FileApp {
    def main(args: Array[String]): Unit = {
        val file = Source.fromFile("C:\\Users\\Administrator\\Desktop\\test.txt")(scala.io.Codec.UTF8)
        readLine()
        readNet()
        def readLine( ): Unit = {
            for (line <- file.getLines()) {
                println(line)
            }
        }

        def readChar(): Unit = {
            for (elem <- file) {
                println(elem)
            }
        }

        def readNet(): Unit = {
            val file = Source.fromURL("http://www.baidu.com")
            for (elem <- file.getLines()) {
                print(elem)
            }
        }
    }
}

9.2 Scala 读取 MySQL 数据

object MySQLApp {
    def main(args: Array[String]): Unit = {
        val url = "jdbc:mysql://localhost:3306/mysql"
        val username = "root"
        val password = "123456"
        var connection: Connection = null
        try{
            classOf[com.mysql.jdbc.Driver]
            connection = DriverManager.getConnection(url, username, password)
            val statement = connection.createStatement()
            val resultSet = statement.executeQuery("select User,Host from user")
            while (resultSet.next()) {
                val host = resultSet.getString("host")
                val user = resultSet.getString("user")
                println(s"$user -> $host")
            }
        }catch {
            case e:Exception => println(e.getMessage)
        } finally {
            if (connection != null)
                connection.close()
        }
    }
}

9.3 Scala 读取 XML 文件

def readValue(): Unit = {
    val xml = XML.load(this.getClass.getClassLoader.getResource("book.xml"))
    // headerField
    val headerField = xml \ "book" \ "field"
    // all fields
    val fields = xml \\ "field"
    // header/field/name
    val fieldAttributes = (xml \ "book" \ "field").map(_ \ "@name")
    // all message == Logon
    val filters = (xml \\ "message").filter(_.attribute("name").exists(_.text.equals("Logon")))
    // header/field content
    val seq = (xml \ "header" \ "field").map(x => (x \ "@name", x.text, x \ "@required"))
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • 函数式编程 引言 Scala中的函数是Java中完全没有的概念。因为Java是完全面向对象的编程语言,没有任何面向...
    义焃阅读 1,253评论 2 5
  • 2.1声明值和变量 val定义的值是不可变的,类似于一个常量。var声明的变量是可变的。 2.2常用类型 Scal...
    Java架构师之路阅读 307评论 0 0
  • 第4章数据结构(重点练习章节) 4.1主要的集合特质 4.1主要的集合特质Scala同时支持可变集合和不可变集合,...
    Java架构师之路阅读 553评论 0 0
  • 3.1if else表达式 在Scala中,几乎所有语法结构都有值。 If语句的返回类型取决于最后一条语句。 Sc...
    Java架构师之路阅读 128评论 0 0
  • Scaladoc是什么:scala api文档,包含了scala所有的api以及使用说明,class、object...
    义焃阅读 2,559评论 0 1