import java.io.{PrintWriter}
import scala.collection.mutable
import scala.io.{Source, StdIn}
import scala.reflect.io.File
case class Person(id: Int, name: String, age: Int)
/**
* Scala 基本笔记
*/
object ScalaLesson extends App {
/**
* 基础-算术
*/
def lesson1() = {
println(1.+(2))
println(2.-(2))
println(2.*(2))
println(2./(2))
println(10 max 2)
}
/**
* 基础-重载
*/
def lesson2() = {
val str = "Hello"(2)
//等同于java中的”Hello“.charAt(2)
println(str)
//实现原理为StringOps包中的一个apply方法:def apply(n:Int): Char
val s = "Hello".apply(2)
println(s)
}
/**
* 基础-字符串操作
*/
def lesson3() = {
val str = "Hello World"
//获取字符串的第一个字符
println(str.head)
//获取字符串的最后一个字符
println(str.last)
//获取字符串前3个字符
println(str.take(3))
//获取字符串后3个字符
println(str.takeRight(3))
//删除字符串前3个字符
println(str.drop(3))
//删除字符串后3个字符
println(str.dropRight(3))
}
/**
* 结构与函数-条件判断
*/
def lesson4(n: Int) = {
//if/else语法结构与java结构一致,在scala中表达式是有值的,这个值就是跟在if/else之后的表达式的值
val s = if (n > 1) 1 else 0
//等同于以下方式,不过在scala中推荐使用val而尽量不使用var可变量
//注:scala中不支持三目运算,scala把java的三目运算结合在了if/else中
var a = 0
if (n > 1) a = 1 else a = 0
println(s)
println(a)
}
/**
* 结构与函数-公共超类
*/
def lesson5(n: Int) = {
//在scala中存在一个公共超类Any,java中只能返回指定类型,scala可以返回不指定的类型,支持混合型表达式
val s = if (n > 0) "Hello World" else 1
println(s)
//在scala中如果if/else中缺失了else后部分,如:
val a = if (n > 0) "Hello World"
//在scala中每个表达式都是有值的,如果缺失了else后部分,为了解决这个问题,在java的基础上引入了一个Unit类,写作(),这样就等同于if(n>0) "Hello World" else ()
//这个()相当于一个无用值,Unit与java中的void相当,区别在于void没有值,Unit有一个“无用”的值。
println(a)
}
/**
* 结构与函数-终止语句
*/
def lesson6(n: Int) = {
//scala中不需要加分号结束,如果是多行写成1行则需要分号结束,但不建议这样写,如:
val s = if (n > 0) {
var r = 1 * n
r -= 1
} else 1
//
}
/**
* 结构与函数-块表达式
*/
def lesson7(n: Int) = {
//与java中的{}一致,但scala的块是一种表达式,所以有值,值为表达式的最后语句返回值
val s = {
val a = 5
a * n
}
println(s)
}
/**
* 结构与函数-输入与输出
*/
def lesson8() = {
//不换行打印
//print("Scala")
//换行打印
//println("你好")
//上面2个打印等同于下面语句
//println("Scala" + "你好")
//带C风格格式化字符串的函数
//printf("Hello,%s! 你是一款很好的语言,你存在有 %y 年了吗?","Scala",10)
//读取控制台一行输入(2.11.0以后的版本使用StdIn)
val name = StdIn.readLine()
println("你输入的姓名是:" + name)
val age = StdIn.readInt()
println("你输入的年龄是:" + age)
}
/**
* 结构与函数-while循环
*/
def lesson9(n: Int) = {
//与java中的while和do循环一致
var i = n
while (i > 0) {
println(i * 3)
i -= 1
}
}
/**
* 结构与函数-for循环
*/
def lesson10(n: Int) = {
//scala中的for循环与java的结构不一样,scala的结构为 for(i <- 表达式)
for (i <- 0 to n) println(i * 3)
println("-----------------这是分割线-------------------")
//在RichInt类中存在 to 这个方法。0 to n 代表的是 0到n的区间(包含n),如果只是0到n-1的话这采用until方法,如下:
for (i <- 0 until n) println(i * 3)
println("-----------------这是分割线-------------------")
val str = "Hello"
var sum = 0
//在循环中不仅可以对数字区间进行遍历,也可以对字符串进行遍历
for (ch <- str) sum += ch
println(sum)
}
/**
* 结构与函数-退出循环
*/
def lesson11(n: Int) = {
//scala中的并没有提供break或者continue语句来退出循环,如果需要break该怎么做,如下:
//1:需要引入import util.control.Breaks._包
import util.control.Breaks._
//break例子
breakable(
for (i <- 0 to 5) {
println(i)
if (i == n) break
}
)
println("-----------------这是分割线-------------------")
//continue例子,需要注意判断要放在最前面
for (i <- 0 to 5) {
breakable {
if (i == n) break
println(i)
}
}
println("-----------------这是分割线-------------------")
//中断嵌套循环
breakable(
for (i <- 0 to 5) {
println(i)
breakable(
for (a <- 1 to 3) {
println("i * a = " + i * a)
if (i * a == 1) break
}
)
}
)
}
/**
* 结构与函数-高级循环
*/
def lesson12(n: Int) = {
//scala支持多个生成器,之间用分号隔开,(等同于多个嵌套for循环)如下:
for (i <- 0 to 3; j <- 1 to 4) println(i * j)
println("-----------------这是分割线-------------------")
//scala支持守卫,以if开头的Boolean表达式(注:if之前没有分号):
for (i <- 0 to 3; j <- 1 to 4 if i < j) println(i * j)
//scala还支持引入循环中的变量:
for (i <- 1 to 3; j <- n to 3) println(i * j)
//for推导式,以yield开始:
val list = for (i <- 1 to 10) yield i % 3
println(list)
}
/**
* 结构与函数-默认参数与带名参数
*/
def lesson13(name: String, n: Int = 18) = {
println(s"你的姓名是:$name,年龄是:$n")
}
/**
* 懒值,只需要在需要懒加载的值或函数前面加 lazy关键字即可,如:
* 只有在调用的时候才执行,不调用的时候不执行
*/
lazy val m = System.currentTimeMillis()
/**
* 结构与函数-异常处理
*/
def lesson14(n: Int): Unit = {
//scala异常的工作原理与java的一样,区别在于scala没有受体异常--不需要声明函数或者方法可能会抛出某种异常
// throw new XXException(xxx)
//捕抓异常采用模式匹配
val a = try {
10 / n
} catch {
case ex: Exception => println(ex.getMessage)
}
}
/**
* 数组操作
*/
def lesson15() = {
import scala.collection.mutable.ArrayBuffer
//定长数组
val arr1 = new Array[Int](5)
println(arr1.toString, arr1.length)
//推导数组,类型根据推导出来,提供初始值的时候不需要new
val arr2 = Array("Hello", "world")
println(arr2.toString, arr2.length)
//根据角标获取值时采用()而不是java的[]
println(arr2(0))
//变长数组:数组缓冲
//创建空的数组缓冲,准备存放整数
val arr3 = ArrayBuffer[Int]()
//用 += 在尾端添加元素
arr3 += 1
//得到ArrayBuffer(1)
arr3 += (1, 3, 4, 8, 2)
//得到ArrayBuffer(1,1,3,4,8,2)
arr3 ++= Array(9, 3, 5)
// 可以用 ++= 操作符追加任何的集合
//得到ArrayBuffer(1,1,3,4,8,2,9,3,5)
arr3.trimEnd(2)
//移除最后2个元素
arr3.trimStart(2)
//移除最前2个元素
//可以在任意位置插入元素(低效)
arr3.insert(1, 3)
//可以在任意地方移除多少个元素(低效)
arr3.remove(1, 2)
//数组缓冲转成Array
arr3.toArray
//数组转数组缓冲
arr1.toBuffer
}
/**
* 数组操作-遍历
*/
def lesson16() = {
val arr1 = Array(1, 2, 6, 3, 8, 4)
//需要下标时
for (i <- 0 until arr1.length) println(i + " : " + arr1(i))
println("-----------------这是分割线-------------------")
//不需要下标时
for (e <- arr1) println(e)
println("-----------------这是分割线-------------------")
//数组转换,采用yield关键字
val r = for (e <- arr1) yield 2 * e
println(r.toList)
}
/**
* 数组操作-常用算法
*/
def lesson17() = {
val arr1 = Array(1, 2, 6, 3, 8, 4)
//求和
println(arr1.sum)
//获取最大值
println(arr1.max)
//获取最小值
println(arr1.min)
//获取平均值
println(if (arr1.nonEmpty) arr1.sum / arr1.length else 0)
//从小到大排序(注:排序得到的是一个新数组缓冲,原数组不会改变)
val r = arr1.sorted
//指定排序
val r1 = arr1.sortWith(_ < _)
println(r.toList)
println(r1.toList)
//数组拼接成字符串
println(r1.toString)
println(r1.mkString)
println(r1.mkString(","))
}
/**
* 数组操作-多维数组
*/
def lesson18(): Unit = {
//与java一样,多维数组是通过数组的数组来实现的。Double的二维数组类型为Array[Array[Double]]
//要构造这样函数可以采用ofDim方法:
val matrix = Array.ofDim[Double](3, 4) //三行四列
//访问这样的数组,使用两对圆括号(row)(column):
matrix(1)(2)
}
/**
* 数组操作-与java的相互操作
*/
def lesson19(): Unit = {
//引入相应的包
import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls", "-al", "/home/cay")
val pb = new ProcessBuilder(command) //Scala转java
import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
val cmd: Buffer[String] = pb.command() //java转Scala
}
/**
* 映射与元组-映射
*/
def lesson20(): Unit = {
//构建一个不可变的映射(建议)
val map = Map("张三" -> 98, "李四" -> 83, "王五" -> 100)
//构建一个可变的映射(不建议)
val map1 = mutable.Map("张三" -> 98, "李四" -> 83, "王五" -> 100)
//构建一个空的映射,需要指定类型参数
val map2 = new mutable.HashMap[String, Int]()
// -> 操作符用来创建对偶
// ("张三" -> 98) 等同于 ("张三" , 98),所以也可以用以下方式定义映射:
val map3 = Map(("张三", 98), ("李四", 83), ("王五", 100))
//获取映射中的值,直接使用(),相当于java中的map.get("张三")
println(map("张三"))
//如果key不存在,则会抛异常,检查映射中是否存在某个key,可以使用contains方法:
val value = if (map.contains("张三")) map("张三") else 0
//可以简写成getOrElse(key,result):
println(map.getOrElse("张三", 0))
//更新可变映射中的值
map1("张三") = 67
//增加可变映射中的值
map1("赵六") = 74
//可以使用 += 增加多个关系
map1 += ("王七" -> 35, "蔡八" -> 86)
//可以使用 -= 移除对应的键值
map1 -= "王五"
//可以使用 + 操作符生成新的映射
val map4 = map + ("王七" -> 35, "蔡八" -> 86)
//映射遍历 for((k,v) <- map)
}
/**
* 映射与元组-元组
*/
def lesson21() = {
//映射是键值对的集合,对偶则是元组(tuple)的最简单形态--元组是不同类型的值的聚集,元组的值是通过将单个的值包含在()构成的,如:
val t = (2, "张三", 4d) //类型分别为 Tuple[Int, String, Double]
//元组的访问可以使用_1、_2、_3这样
println(t._1)
println(t._2)
println(t._3)
//也可以在返回值的时候就定义下来,通常使用这种,这样更为直观的表达出返回的结果分别代表什么
val (first, second, third) = t
println(first)
println(second)
println(third)
}
/**
* 映射与元组-拉链操作
*/
def lesson22(): Unit = {
//使用元组的原因之一是吧多个值绑定在一起,以方便它们能够被一起处理,这个通常可以使用zip方法来完成,如下:
val a1 = Array("张三", "李四", "王五")
val a2 = Array(55, 26, 96)
val p = a1.zip(a2) //得到的对偶数组为Array(("张三",55),("李四",26),("王五",96))
//还可以把对偶数组转成映射
println(p.toMap)
//得到结果 Map(张三 -> 55, 李四 -> 26, 王五 -> 96)
}
/**
* 对象-单例对象
* 在Scala中没有静态方法或者静态字段,可以通过object语法结构来定义
*
*/
object Accounts { //伴生对象
private var lastNumber = 0
def newUniqueNumber() = {
lastNumber += 1; lastNumber
}
}
/**
* 对象-伴生对象
* 在Scala中没有静态方法或者静态字段,可以通过object语法结构来定义
*
*/
class Accounts {
val id = Accounts.newUniqueNumber()
}
/**
* 对象-扩展类或特质对象
*/
abstract class UndoableAction(val desc: String) {
def undo(): Unit
def redo(): Unit
}
object DoNothingAction extends UndoableAction("Do nothing") {
override def undo(): Unit = {}
override def redo(): Unit = {}
}
//DoNothingAction可以被所有所需要这个缺省行为的地方共用
val actions = Map("open" -> DoNothingAction, "save" -> DoNothingAction)
/**
* 对象-应用程序对象
* 每个Scala程序都必须从一个对象main方法开始,也可以扩展App特质
* object Hello{
* def main(args:Array[String]) {
* println("Hello World")
* }
* }
*/
/**
* 对象-枚举
* scala中并没有枚举类型,不过提供了一个Enumeration助手类,可以用于产出枚举
*/
object TrafficLightColor extends Enumeration {
val Red = Value(0, "Stop")
val Yellow = Value(10)
val Green = Value("Go")
}
def lesson23(): Unit = {
println(TrafficLightColor.Red)
println(TrafficLightColor.Yellow)
println(TrafficLightColor.Green)
}
/**
* 文件操作-读取文件
*/
def lesson24(): Unit = {
//以指定的GBK字符集读取文件,第一个参数可以是字符串或者是java.io.File
val source = Source.fromFile("贪腐词库.txt", "GBK")
//获取所有行
val lines = source.getLines()
//将所有行放到list中
val list = lines.toList
//将文件用逗号串起来(注:旧版采用source.mkString,新版中获取不到值)
val str = list.mkString
//println("------------"+str)
//迭代打印集合
//list.foreach(it=>println(it))
//关闭流
source.close()
}
/**
* 文件操作-从URL读取文件
*/
def lesson25(): Unit = {
val source = Source.fromURL("https://www.baidu.com", "UTF-8")
//获取所有行
val lines = source.getLines()
//将所有行放到list中
val list = lines.toList
//将文件用逗号串起来(注:旧版采用source.mkString,新版中获取不到值)
val str = list.mkString
//println("------------"+str)
//迭代打印集合
list.foreach(it => println(it))
//关闭流
source.close()
}
/**
* 文件操作-读取二进制文件
*/
def lesson26(): Unit = {
val file = File("其他词库.txt")
val in = file.inputStream()
val bytes = new Array[Byte](file.length.toInt)
in.read(bytes)
println(bytes.mkString(","))
in.close()
}
/**
* 文件操作-写入文件
*/
def lesson27() = {
//scala中没有内建对文件的支持,所以使用java.io.PrintWriter
val out = new PrintWriter("test.txt")
for (i <- 1 to 100) out.println(i)
}
/**
* 正则表达式
*/
def lesson28() = {
//采用String中的r方法
val pattern = "[0-9]+".r
println(pattern findAllIn "02,2")
}
/**
* 操作符
*/
def lesson29() = {
//在scala中可以使用任意序列的操作字符作为定义,如:
val * = "ere"
val & = "ere"
val ! = "ere"
//一旦遇到命名定义是scala关键字的还可以采用反引号来拯救(当然平时还是注意少用scala的关键字来命名)
val `type` = 354
//还可以使用 a 标识符 b 这样写
//1 to 10 //实际上是调用了 1.to(10) 的方法
//1-> 10 //等同调用 1.—>(10) 的方法
//1 toString //等同于 1.toString ,以上均为一元操作符,点号可以省略
//赋值操作符 a 操作符= b 等同于 a = a + b
//1 += 2 //等同于 1 = 1 + 2
//结合性,已冒号结束,操作符是右结合
//1::2::Nil //等同于 1::(2::Nil)
}
import math._
/**
* 高阶函数-值函数
*/
def lesson30() = {
val num = 3.14
//把 ceil函数赋值给fun
val fun = ceil _
val a = Array(2.14, 1.42, 2.0).map(fun)
println(a.mkString(","))
}
/**
* 高阶函数-匿名函数
*/
def lesson31() = {
val s = (x: Double) => 3 * x
//等同于 def s(x:Double) = 3 * x
println(s(3))
}
/**
* 高阶函数-带函数参数的函数
*/
def lesson32(f: (Double) => Double) = {
f(0.25)
}
//对于只出现一次的参数,可以使用_替代
//lesson32(ceil _)
/**
* 高阶函数-一些有用的高阶函数
*/
def lesson33() = {
val list = List("张三", "李四", "王五")
//map方法,遍历应用到集合中的所有元素,并返回全新的结果集合
println(list.map(it => it -> "你好"))
//foreach方法,遍历集合的所有元素,但不返回结果(对于只出现一次的参数,可以使用_替代)
list.foreach(println(_))
//filter方法,根据条件过滤生成全新的集合
val f = list.filter(_ != "张三")
println(f)
//sortWith方法,指定参数排序,返回全新的集合
println(list.sortWith(_ > _))
//sorted方法,从低到高排序,返回全新的集合
println(list.sortWith(_ > _).sorted)
//groupBy方法,根据指定参数进行合并分组,返回map[object,List[object]]集合
val userList = List(Person(1, "张三", 23), Person(2, "李四", 45), Person(1, "王五", 30))
val map: Map[Int, List[Person]] = userList.groupBy(_.id)
//Map遍历,_1代表key,_2代表value
map.foreach(it => {
println(it._1)
println(it._2)
})
//exists方法,遍历判断条件是否成立
println(list.exists(_ == "张三"))
//distinct方法,去除重复的元素
println(list.distinct)
}
/**
* 集合之间的操作
*/
def lesson34() = {
//注:在scala中不可变集合进行操作生成的都为新的集合,原有集合不发生改变
val list = List(1, 2, 3)
val map = Map(1 -> "java", 2 -> "scala", 3 -> "php")
//List追加元素, 后面追加采用 :+ 前面追加采用 +:
println(list :+ 2)
//List移除元素
println(list.toSet - 2)
//List第一位置增加元素
println(5 +: list)
//2个List合并,采用:::或者 ++ 或者 | 或者++:
println(list ++ List(6))
println(list ::: List(6))
println(list ++: List(6))
println(list.toSet | List(7).toSet)
//list中移除另外一个List中所有包含的元素,采用 -- 或者 &~
println(list.toSet -- List(2))
println(list.toSet &~ List(2).toSet)
//俩个list的交集
println(list.toSet & List(2).toSet)
}
/**
* 模式匹配-更好的switch
*/
def lesson35(n: Int) = {
//scala的switch更优雅的处理方式,在c和类C语言中,模式匹配必须在末尾显式的使用break语句进行退出switch,scala不会有这样的问题
//match与if类似,都是使用表达式。在很多时候match的使用更优雅与if/else if,这样不会出现多层嵌套的情况
val result = n match {
case 1 => "张三"
case 2 => "李四"
case _ => "王五"
}
println(result)
//模式用还可以使用守卫,如下:
val r = n match {
case 1 => "张三"
case a if (a > 5) => "李四"
case _ => "王五"
}
println(r)
//类型匹配,如下:
val ar: Any = if (n > 0) 1 else "Hello"
val s = ar match {
case i: Int => "张三"
case s: String => "李四"
case _ => "王五"
}
println(s)
}
/**
* 模式匹配-Option类型
*/
def lesson36() = {
//生成Option带值的元素
val o: Option[String] = Some("张三")
println(o)
//生成不带值的Option元素
val o1: Option[Nothing] = None
println(o1)
//Option元素获取值,采用get方法
println(o.get)
//但是直接采用get方法很容易出现 java.util.NoSuchElementException: None.get异常,scala提供了组合方法getOrElse
println(o1.getOrElse(""))
}
/**
* 模式匹配-断言
*/
def lesson37(n: Int) = {
//在scala中与java一样使用断言,格式 assert(条件,提示语)
assert(n > 1, "参数不能小于2")
}
def lesson38() = {
(0 to 10).map(println(_))
}
lesson38()
}