文章目录
- Scala 与 Java 的最大区别是:Scala 语句末尾的分号 ; 是可选的。
- 大小写敏感
- 类名第一个字母大写
- 方法名第一个字母小写
- 定义包
package
- 引入包
import java.awt._ // 引入包内所有成员
基本数据类型和操作
基本数据类型
Scala的数据类型包括:Byte、Char、Short、Int、Long、Float、Double和 Boolean。对于字符串,Scala用java.lang.String 类来表示字符串。
操作符
-
在Scala中,可以使用加(+)、减(-) 、乘(*) 、除(/) 、余数(%)等操作 符,而且,这些操作符就是方法。例如,5 + 3和(5).+(3)是等价的。
-
在Scala中并没有提供++和–操作符。
富包装类
-
对于基本数据类型,除了以上提到的各种操作符外,Scala 还提供了许多常用运算的方法,只是这些方法不是在基本类 里面定义,还是被封装到一个对应的富包装类中
-
每个基本类型都有一个对应的富包装类,例如Int有一个 RichInt类、String有一个RichString类,这些类位于包 scala.runtime中
-
当对一个基本数据类型的对象调用其富包装类提供的方法, Scala会自动通过隐式转换将该对象转换为对应的富包装类 型,然后再调用相应的方法。例如:3 max 5
Range
可以用一下命令来产生for循环时的数值序列:
1 to 5
1 util5
1 to 10 by 2
输入
import scala.io._. // read_xxx 在这个包中
var i = readInt()
var l = readLine()
var c = readChar()
var b = readBoolean()
输出
print()
、println()
和printf()
读写文件
- Scala 进行文件写操作,直接用的都是 java中 的 I/O 类 (java.io.File)
import java.io._
object Test {
def main(args: Array[String]) {
val writer = new PrintWriter(new File("test.txt" ))
writer.write("菜鸟教程")
writer.close()
}
}
- 可以使用Scala.io.Source的getLines方法实现对文件中所 有行的读取
import scala.io.Source
object Test {
def main(args: Array[String]) {
println("文件内容为:" )
// 1.
Source.fromFile("test.txt" ).foreach{
print
}
// 2.返回结果是个迭代器
Source.fromFile("test.txt" ).getlines
}
}
控制结构
条件: if
if(布尔表达式 1){
// 如果布尔表达式 1 为 true 则执行该语句块
}else if(布尔表达式 2){
// 如果布尔表达式 2 为 true 则执行该语句块
}else if(布尔表达式 3){
// 如果布尔表达式 3 为 true 则执行该语句块
}else {
// 如果以上条件都为 false 执行该语句块
}
循环:While/do…while/for
for( a <- 1 to 10){
println( "Value of a: " + a );
}
for( a <- 1 to 3; b <- 1 to 3){
println( "Value of a: " + a );
println( "Value of b: " + b );
}
val numList = List(1,2,3,4,5,6);
for( a <- numList ){
println( "Value of a: " + a );
}
//for 循环过滤
for( a <- numList if a != 3; if a < 8 ){
println( "Value of a: " + a );
}
//for 使用 yield
var retVal = for{ a <- numList
if a != 3; if a < 8
}yield a
数据结构
容器(Collection)
- Scala提供了一套丰富的容器(collection)库,包括列表 (List)、数组(Array)、集合(Set)、映射(Map)等
- 根据容器中元素的组织方式和操作方式,可以区分为有序 和无序、可变和不可变等不同的容器类别
- Scala用了三个包来组织容器类,分别是scala.collection 、 scala.collection.mutable(可变集)和scala.collection.immutable(不可变集)
- 它为所有的容器类定义了公用的
foreach
方法,用于对容器元素进行遍历操作
列表(List):
Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。。
几个要知道的符号:
- 列表的元素类型 T 可以写成
List[T]
- 构造列表的两个基本单位是 Nil 和 ::。Nil 也可以表示为一个空列表。
定义
有两种方式:
// 字符串列表
val site: List[String] = List("Runoob", "Google", "Baidu")
val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil))
// 空列表
val empty: List[Nothing] = List()
val empty = Nil
// 二维列表
val dim: List[List[Int]] =
List(
List(1, 0, 0),
List(0, 1, 0),
List(0, 0, 1)
)
val dim = (1 :: (0 :: (0 :: Nil))) ::
(0 :: (1 :: (0 :: Nil))) ::
(0 :: (0 :: (1 :: Nil))) :: Nil
列表基本操作
head
返回列表第一个元素tail
返回一个列表,包含除了第一元素之外的其他元素isEmpty
在列表为空时返回true
println( "第一网站是 : " + site.head )
println( "最后一个网站是 : " + site.tail )
println( "查看列表 site 是否为空 : " + site.isEmpty )
连接列表
可以使用 ::: 运算符或 List.::😦) 方法或 List.concat() 方法来连接两个或多个列表。
// 使用 ::: 运算符
var fruit = site1 ::: site2
println( "site1 ::: site2 : " + fruit )
// 使用 List.:::() 方法
fruit = site1.:::(site2)
println( "site1.:::(site2) : " + fruit )
// 使用 concat 方法
fruit = List.concat(site1, site2)
println( "List.concat(site1, site2) : " + fruit )
Scala List 常用方法
-
List.fill(): 我们可以使用 List.fill() 方法来创建一个指定重复数量的元素列表:
val site = List.fill(3)("Runoob") // 重复 Runoob 3次 println( "site : " + site ) val num = List.fill(10)(2) // 重复元素 2, 10 次 println( "num : " + num )
-
List.tabulate() 方法是通过给定的函数来创建列表。
方法的第一个参数为元素的数量,可以是二维的,第二个参数为指定的函数,我们通过指定的函数计算结果并返回值插入到列表中,起始值为 0,实例如下:
// 通过给定的函数创建 5 个元素 val squares = List.tabulate(6)(n => n * n) println( "一维 : " + squares ) // 创建二维列表 val mul = List.tabulate( 4,5 )( _ * _ ) println( "多维 : " + mul )
输出:
一维 : List(0, 1, 4, 9, 16, 25) 多维 : List(List(0, 0, 0, 0, 0), List(0, 1, 2, 3, 4), List(0, 2, 4, 6, 8), List(0, 3, 6, 9, 12))
// +: 为列表添加元素 (:朝着list)
"xxx"+:site // 返回:List(xxx, Runoob, Google, Baidu)
// :+
site :+ "xxx" // 返回 List[String] = List(Runoob, Google, Baidu, xxx)
// :: 在列表开头添加元素
"xxx"::site // 返回:List(xxx, Runoob, Google, Baidu)
// :::在列表开头添加指定列表的元素
site ::: nums // val res35: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
// ++ 拼接
site++nums // 返回:val res34: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
// ++:和:++
site :++ nums // val res31: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
site ++: nums // val res29: List[Any] = List(Runoob, Google, Baidu, 1, 3, 2)
site.apply(2) // apply 通过列表索引获取元素
// val res42: String = Baidu
site.contains("baidu")
// val res43: Boolean = false
val nums = List(1,1,2,3); nums.distinct
// val res45: List[Int] = List(1, 2, 3)
nums.exists(x=>x>1) // 判断列表中指定条件的元素是否存在。
// val res47: Boolean = true
nums.filter(x=>x>1) // 输出符号指定条件的所有元素。
//val res48: List[Int] = List(2, 3)
site.foreach(print(_)) // 将函数应用到列表的所有元素
// RunoobGoogleBaidu
site.indexOf("Baidu")
//val res69: Int = 2
site.map(x=>x+"xxx")
// val res71: List[String] = List(Runoobxxx, Googlexxx, Baiduxxx)
site.mkString(";") // 使用分隔符将列表所有元素作为字符串显示
// val res74: String = Runoob;Google;Baidu
site.mkString // 列表所有元素作为字符串显示
// val res75: String = RunoobGoogleBaidu
site.reverse
// val res77: List[String] = List(Baidu, Google, Runoob)
site.toString()
// val res86: String = List(Runoob, Google, Baidu)
集合(Set)
- 集合包括可变集和不可变集,
- 默认是不可变的,如果要声明一个可变集,则需要提前引入scala.collection.mutable.Set
import scala.collection.mutable.Set // 可以在任何地方引入 可变集合
val mutableSet = Set(1,2,3)
// val mutableSet: scala.collection.mutable.Set[Int] = HashSet(1, 2, 3)
mutableSet.add(4)
mutableSet.remove(1)
num1 & num2 // 交集 或者.&或.intersect 取交集
// val res97: scala.collection.mutable.Set[Int] = HashSet(20, 9)
num1 &~ num2 // 差集
//val res98: scala.collection.mutable.Set[Int] = HashSet(5, 6, 45, 30)
num2 &~ num1 // 差集
//val res99: scala.collection.mutable.Set[Int] = HashSet(50, 35, 55, 60)
num1 ++ num2 // 连接集合
// val res101: scala.collection.mutable.Set[Int] = HashSet(35, 5, 6, 9, 45, 50, 20, 55, 60, 30)
映射(Map)
- Map 有两种类型,可变与不可变,区别在于可变对象可以修改它,而不可变对象不可以。
- 默认情况下 Scala 使用不可变 Map。如果你需要使用可变集合,你需要显式的引入 import scala.collection.mutable.Map 类
- 更多参考API
// 空哈希表,键为字符串,值为整型
var A:Map[Char,Int] = Map()
// Map 键值对演示
val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF")
println( "colors 中的键为 : " + colors.keys )
println( "colors 中的值为 : " + colors.values )
println( "检测 colors 是否为空 : " + colors.isEmpty )
colors.keys.foreach{ i =>
print( "Key = " + i )
println(" Value = " + colors(i) )}
colors.toSet
// val res106: scala.collection.immutable.Set[(String, String)] = Set((red,#FF0000), (azure,#F0FFFF))
迭代器(Iterator)
- 在Scala中,迭代器(Iterator)不是一个集合,但是,提供了 访问集合的一种方法
- 迭代器包含两个基本操作:next和hasNext。next可以返回迭代器的下一个元素,hasNext用于检测是否还有下一个元素
val it = Iterator("Baidu", "Google", "Runoob", "Taobao")
while (it.hasNext){
println(it.next())
}
it.size
it.length
数组(Array)
- 数组是一种可变的、可索引的、元素具有相同类型的数据集合,它是各种高 级语言中最常用的数据结构。
- Scala提供了参数化类型的通用数组类Array[T], 其中T可以是任意的Scala类型,可以通过显式指定类型或者通过隐式推断来 实例化一个数组。
- Array提供了函数ofDim来定义二维和三维数组
- 采用Array类型定义的数组属于定长数组,其数组长度在初始化后就不能改变。如果要定义变长数组,需要使用ArrayBuffer参数类型,其位于包 scala.collection.mutable中。
- 更多参考
import Array._
// 定义1
var z = Array("Runoob", "Baidu", "Google")
// 定义2
var z = new Array[String](3)
z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google"
// 输出所有数组元素
for ( x <- myList ) {
println( x )
}
myList.length
// 多维数组,通过ofDim定义
var myMatrix = ofDim[Int](3,3)
for (i <- 0 to 2) {
for ( j <- 0 to 2) {
myMatrix(i)(j) = j;
}
}
// 合并数组
var myList3 = concat( myList1, myList2)
元组(Tuple)
- 与列表一样,元组也是不可变的,但与列表不同的是元组可以包含不同类型的元素。
- 目前 Scala 支持的元组最大长度为 22。
- 我们可以使用 t._1 访问第一个元素, t._2 访问第二个元素
val t = (1, 3.14, "Fred")
val t = (4,3,2,1)
val sum = t._1 + t._2 + t._3 + t._4 // 访问元祖元素;返回10
t.productIterator.foreach{ i =>println("Value = " + i )} //Tuple.productIterator() 迭代输出元组的所有元素
Option
- Scala Option(选项)类型用来表示一个值是可选的(有值或无值)。
- Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None 。
- 可以使用 getOrElse() 方法来获取元组中存在的元素或者使用其默认的值,
val myMap: Map[String, String] = Map("key1" -> "value")
val value1: Option[String] = myMap.get("key1") // Some("value1")
val value2: Option[String] = myMap.get("key2") // None
def show(x: Option[String]) = x match {
case Some(s) => s
case None => "?"
}
print(show(value1) ) // value
print(show(value2) ) // ?
value1.getOrElse(0) // value
value2.getOrElse(0) // 0
value1.filter(_=="value")
// val res6: Option[String] = Some(value)
面向对象编程基础
Scala 方法与函数
- Scala 有方法与函数,二者在语义上的区别很小。Scala 方法是类的一部分,而函数是一个对象可以赋值给一个变量。换句话来说在类中定义的函数即是方法。
- Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
- Scala 中使用 val 语句可以定义函数,def 语句定义方法。
方法
- 方法定义由一个 def 关键字开始,紧接着是可选的参数列表,一个冒号 : 和方法的返回类型,一个等于号 = ,最后是方法的主体。
- 如果方法没有返回值,可以返回为 Unit,这个类似于 Java 的 void,
def functionName ([参数列表]) : [return type] // 声明
def functionName ([参数列表]) : [return type] = { // 定义
function body
return [expr]
}
// 举例
object Test {
def main(args: Array[String]) {
println( "Returned Value : " + addInt(5,7) );
}
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
类
class Point(xc: Int, yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐标点: " + x);
println ("y 的坐标点: " + y);
}
def increment():Unit = {x += 1}
def current(): Int = {value} // 如果操作语句只有一句
}
object Test {
def main(args: Array[String]) {
val pt = new Point(10, 20);
// 移到一个新的位置
pt.move(10, 10);
}
}
对象
单例对象
- Scala并没有提供Java那样的静态方法或静态字段,但是,可以采用 object关键字实现单例对象,具备和Java静态方法同样的功能。
伴生对象
- 在Java中,我们经常需要用到同时包含实例方法和静态 方法的类,在Scala中可以通过伴生对象来实现。
- 当单例对象与某个类具有相同的名称时,它被称为这个 类的“伴生对象”。
- 类和它的伴生对象必须存在于同一个文件中,而且可以 相互访问私有成员(字段和方法)。
继承
Scala继承一个基类跟Java很相似, 但我们需要注意以下几点:
- 1、重写一个非抽象方法必须使用override修饰符。
- 2、只有主构造函数才可以往基类的构造函数里写参数。
- 3、在子类中重写超类的抽象方法时,不需要使用override关键字。
特质
模式匹配
函数式编程
实例WordCount:
import java.io.File
import scala.io.Source
object WordCount{
def main(args:Array[String]):Unit={
val dirfile=new File("wordCount")
val files = dirfile.listFiles
for(file <- files) print(file)
val listFiles = files.toList
val wordsMap = scala.collection.mutable.Map[String,Int]()
listFiles.foreach(file => Source.fromFile(file).getLines().foreach(line => line.split(" ").foreach(
word => {
if(wordsMap.contains(word)){
wordsMap(word) += 1
}else{
wordsMap+=(word->1)
}
}
)))
println(wordsMap)
for((key,value)<-wordsMap) print(key + ": " + value)
}
}