1. 特點:
- Scala是一門多范式編程語言,集成了面向對象編程和函數式編程等多種特性。
- Scala運行在虛擬機上,并兼容現有的Java程序。
- Scala源代碼被編譯成java字節(jié)碼,所以運行在JVM上,并可以調用現有的Java類庫。
- Scala和Java最大的區(qū)別是:Scala語句末尾的分號(;)是可選的!
- Scala編譯運行:
先編譯:scalac HelloScala.scala 將會生成兩個文件:HelloScala$.class和HelloScala.class
再運行:scala HelloScala
輸出結果:hello scala!!!
2. Scala基本語法
- 區(qū)分大小寫
- 類名首字母大寫駝峰形式(MyFirstScalaClass)
- 方法名稱首字母小寫駝峰形式(myMethodName())
- 程序文件名應該與對象名稱完全匹配
- def main(args:Array[String]):scala程序從main方法開始處理,程序的入口。
- Scala注釋:分為多行/**/和單行//
- 換行符:Scala是面向行的語言,語句可以用分號(;)結束或換行符(println())
- 定義包有兩種方法:
1、package com.ahu
class HelloScala
2、package com.ahu{
class HelloScala
}
- 引用:import java.awt.Color
如果想要引入包中的幾個成員,可以用selector(選取器):
import java.awt.{Color,Font}
// 重命名成員
import java.util.{HashMap => JavaHashMap}
// 隱藏成員 默認情況下,Scala 總會引入 java.lang._ 、 scala._ 和 Predef._,所以在使用時都是省去scala.的
import java.util.{HashMap => _, _} //引入了util包所有成員,但HashMap被隱藏了
3. 數據類型
Scala與Java有著相同的數據類型,下面列出一些Scala有的數據類型。
- Unit:表示無值,和其他語言的void一樣。
- Null:null或空引用。
- Nothing:是Scala的類層級的最低端,是任何其他類型的子類型。
- Any:是所有其他類的超類。
- AnyRef:是Scala所有引用類的基類。
- 多行字符串的表示方法:
val foo ="""第一行
第二行
第三行"""
4. 變量
- 在Scala中,使用關鍵字“var”聲明變量,使用關鍵字“val”聲明常量。
var myVar1 : String = "foo"
var myVar2 : Int
val myVal = "Hello,Scala!"
- Scala多個變量聲明:
val xmax, ymax = 100 // xmax,ymax都聲明為100
5. 訪問修飾符
Scala訪問修飾符和Java基本一樣,分別有private、protected、public。
默認情況下,Scala對象的訪問級別是public。
- 私有成員:用private關鍵字修飾的成員僅在包含了成員定義的類或對象內部可見。
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正確
}
(new Inner).f() // 錯誤
}
}
- 保護成員:Scala比Java中更嚴格。只允許保護成員在定義了該成員的類的子類中被訪問。
package p{
class Super{
protected def f() {println("f")}
}
class Sub extends Super{
f()
}
class Other{
(new Super).f() // 錯誤
}
}
- 公共成員:默認public,這樣的成員在任何地方都可以被訪問。
class Outer{
class Inner{
def f(){println("f")}
class InnerMost{
f() // 正確
}
}
(new Inner).f() // 正確
}
- 作用域保護:Scala中,訪問修飾符可以通過使用限定詞強調。
- private[x] 或者 protected[x]
- private[x]:這個成員除了對[...]中的類或[...]中的包中的類及他們的伴生對象可見外,對其他的類都是private。
5. 運算符
Scala運算符:和Java一樣,這里就不再浪費時間一一介紹了。
算術運算符、關系運算符、邏輯運算符、位運算符、賦值運算符。
- Scala if...else語句:和Java一樣
- Scala循環(huán):和Java一樣。while循環(huán)、do...while循環(huán)、for循環(huán)
6. Scala方法與函數
- Scala 有方法與函數,二者在語義上的區(qū)別很小。
- Scala 方法是類的一部分,而函數是一個對象可以賦值給一個變量。換句話來說在類中定義的函數即是方法。
- Scala 中的方法跟 Java 的類似,方法是組成類的一部分。
- Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。
- Scala 中使用 val 語句可以定義函數,def 語句定義方法。
用一個例子來說明函數的定義和函數調用。
class Test{
def m(x: Int) = x + 3
val f = (x: Int) => x + 3
}
注意:有些翻譯上函數(function)與方法(method)是沒有區(qū)別的。
- 方法的聲明
Scala 方法聲明格式如下:
def functionName ([參數列表]) : [return type]
如果你不寫等于號和方法主體,那么方法會被隱式聲明為抽象(abstract),包含它的類型于是也是一個抽象類型。
- 方法的定義
方法定義由一個 def 關鍵字開始,緊接著是可選的參數列表,一個冒號 : 和方法的返回類型,一個等于號 = ,最后是方法的主體。
Scala 方法定義格式如下:
def functionName ([參數列表]) : [return type] = {
function body
return [expr]
}
以上代碼中 return type 可以是任意合法的 Scala 數據類型。參數列表中的參數可以使用逗號分隔。
以下方法的功能是將兩個傳入的參數相加并求和:
object add{
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
如果方法沒有返回值,可以返回為 Unit,這個類似于 Java 的 void, 實例如下:
object Hello{
def printMe( ) : Unit = {
println("Hello, Scala!")
}
}
- 方法調用
Scala 提供了多種不同的方法調用方式:
以下是調用方法的標準格式:
functionName( 參數列表 )
如果方法使用了實例的對象來調用,我們可以使用類似java的格式 (使用 . 號):
[instance.]functionName( 參數列表 )
以下實例演示了定義與調用方法的實例:
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
}
}
7. Scala閉包:
閉包是一個函數,返回值依賴于聲明在函數外部的一個或多個變量。
例子:
object Test{
def main(args: Array[String]){
println("muliplier(1) value = " + muliplier(1))
println("muliplier(2) value = " + muliplier(2))
}
var factor = 3 // 定義在函數外的自由變量
val muliplier = (i:Int) => i * factor // muliplier函數變量就是一個閉包
}
輸出結果:
muliplier(1) value = 3
muliplier(2) value = 6
在 multiplier 中有兩個變量:i 和 factor。其中的一個 i 是函數的形式參數,在 multiplier 函數被調用時,i 被賦予一個新的值。然而,factor不是形式參數,而是自由變量,
這里我們引入一個自由變量 factor,這個變量定義在函數外面。
這樣定義的函數變量 multiplier 成為一個"閉包",因為它引用到函數外面定義的變量,定義這個函數的過程是將這個自由變量捕獲而構成一個封閉的函數。
8. Scala字符串
Scala中可以創(chuàng)建兩中字符串:一種是不可修改的,一種是可以修改的。
- 創(chuàng)建不可修改的字符串
val greeting:String = "Hello World!";
- 創(chuàng)建可以修改的字符串
object Test{
def main(args: Array[String]){
val buf = new StringBuilder;
buf += 'a' // 添加一個字符
buf ++= "bcdef" // 添加一個字符串
println(buf.toString); // 輸出:abcdef
}
}
- 字符串長度:xxx.length()
- 字符串連接:可以用concat()方法或者用加號
object Test {
def main(args: Array[String]) {
var str1 = "字符串1:";
var str2 = "字符串2";
var str3 = "字符串3:";
var str4 = "字符串4";
println( str1 + str2 ); // 字符串1:字符串2
println( str3.concat(str4) ); // 字符串3:字符串4
}
}
- 創(chuàng)建格式化字符串:
String類中可以使用printf()方法來格式化字符串并輸出。
object Test{
def main(args:Array[String]){
var floatVar = 12.456
var intVar = 2000
var stringVar = "字符串變量"
var fs = printf("浮點型變量為 " +
"%f,整形變量為 %d, 字符串為 " +
"%s", floatVar, intVar, stringVar)
println(fs) // 浮點型變量為 12.456000, 整型變量為 2000, 字符串為 字符串變量
}
}
9. Scala數組
- 聲明數組
//第一種
var z:Array[String] = new Array[String](3);
//第二種
var z = new Array[String](3);
//賦值
z(0)= "value1";
z(1) = "value2";
z(2) = "value3";
//第三種
var z = Array("value1","value2","value3");
- 處理數組
object Test {
def main(args: Array[String]): Unit = {
var myList = Array(1.1,2.2,3.3,4.4);
//輸出所有元素
for(x <- myList){
println(x);
}
//計算數組所有元素的總和
var total = 0.0;
for(i <- 0 to (myList.length-1)){
total += myList(i);
}
println("total: "+total)
//查找數組中的最大值
var max = myList(0);
for(i <- 0 to (myList.length-1)){
if(myList(i) > max){
max = myList(i);
}
}
println("max: " + max)
}
}
- 多維數組
import Array._
object Test {
def main(args: Array[String]): Unit = {
//定義數組
val myMatrix = ofDim[Int](3,3);
//創(chuàng)建矩陣
for(i <- 0 to 2){
for(j <- 0 to 2){
myMatrix(i)(j) = j;
}
}
//打印矩陣
for(i <- 0 to 2){
for(j <- 0 to 2){
print(" " + myMatrix(i)(j));
}
println();
}
}
}
結果:
- 合并數組
import Array._
object Test {
def main(args: Array[String]): Unit = {
var myList1 = Array(1.1, 2.2, 3.3, 4.4)
var myList2 = Array(5.5, 6.6, 7.7, 8.8)
// 使用concat()合并
var myList3 = concat(myList1, myList2)
// 輸出所有數組元素
for (x <- myList3) {
println(x)
}
}
}
結果:
- 創(chuàng)建區(qū)間數組:使用range(x,y,z)創(chuàng)建區(qū)間數組,數值范圍大于等于x,小于y。z表示步長,默認為1。
import Array._
object Test {
def main(args: Array[String]): Unit = {
var myList1 = range(10,20,2);
var myList2 = range(10,20);
for (x <- myList1) {
print(" " + x)
}
println(); //輸出:10 12 14 16 18
for(x <- myList2){
print(" " + x); //輸出:10 11 12 13 14 15 16 17 18 19
}
}
}
10. Scala集合
Scala集合分為可變集合和不可變集合
可變集合:可以在適當的時候擴展或更新,也就是可以修改、添加、移除集合元素。
不可變集合:永遠不可改變。但可以模擬添加、移除、更新操作,但是這些操作將在每一種情況下都返回一個新的集合, 同時使原來的集合不發(fā)生改變。
- Scala List:List的特征是其元素以線性方式存儲,集合中可以存放重復對象。
- Scala Set:Set是最簡單的一種集合。集合中的對象不按特定的方式排序,并且沒有重復對象。
- Scala Map:Map 是一種把鍵對象和值對象映射的集合,它的每一個元素都包含一對鍵對象和值對象。
- Scala 元組:元組是不同類型的值的集合
- Scala Option:Option[T] 表示有可能包含值的容器,也可能不包含值。
- Scala Iterator:迭代器不是一個容器,更確切的說是逐一訪問容器內元素的方法。
object Test {
def main(args: Array[String]): Unit = {
//定義整型List
val list = List(1, 2, 3, 4);
//定義Set
val set = Set(1, 3, 5, 7);
//定義Map
val map = Map("one" -> 1, "two" -> 2, "three" -> 3);
//創(chuàng)建兩個不同類型的元組
val x = (10, "tom");
//定義Option
val option: Option[Int] = Some(5);
//迭代器示例
val it = Iterator("one", "two", "three", "four")
while (it.hasNext) { // 檢測集合中是否還有元素
println(it.next()) // 返回迭代器的下一個元素,并更新迭代器的狀態(tài)
}
val ita = Iterator(1, 2, 3, 4, 5)
val itb = Iterator(11, 22, 33, 44, 55)
//println(ita.max) // 查找最大元素
// println(itb.min) // 查找最小元素
println(ita.size) // 獲取迭代器的長度
println(itb.length) // 獲取迭代器的長度
}
}
11. Scala類和對象
類是對象的抽象,而對象是類的具體實例。
類是抽象的,不占用內存,而對象是具體的,占用存儲空間。
類是用于創(chuàng)建對象的藍圖,它是一個定義包括在特定類型的對象中的方法和變量的軟件模板。
class Point(xc:Int, yc:Int) {
var x:Int = xc;
var y:Int = yc;
def move(dx:Int,dy:Int): Unit ={
x = x + dx;
y = y + dy;
println("x的坐標是:" + x);
println("y的坐標是:" + y);
}
}
object Test {
def main(args: Array[String]): Unit = {
val pt = new Point(10,20);
pt.move(10,20);
}
}
12. Scala繼承
Scala繼承一個基類跟Java很相似, 但我們需要注意以下幾點:
1、重寫一個非抽象方法必須使用override修飾符。
2、只有主構造函數才可以往基類的構造函數里寫參數。
3、在子類中重寫超類的抽象方法時,你不需要使用override關鍵字。
class Point(xc:Int, yc:Int) {
var x:Int = xc;
var y:Int = yc;
def move(dx:Int,dy:Int): Unit ={
x = x + dx;
y = y + dy;
println("x的坐標是:" + x);
println("y的坐標是:" + y);
}
var name = "";
override def toString: String = getClass.getName + "[name=" + name + "]";
}
class Location(val xc: Int, val yc: Int, val zc: Int)
extends Point(xc, yc) {
var z: Int = zc;
def move(dx: Int, dy: Int, dz: Int) = {
x = x + dx;
y = y + dy;
z = z + dz;
}
var salary = 0.0;
override def toString: String = super.toString + "[salary="+ salary+ "]";
}
object Test {
def main(args: Array[String]): Unit = {
val lo = new Location(10,20,30);
lo.move(10,10,5);
lo.name = "location";
lo.salary = 35000.0;
println(lo);
}
}
13. Scala單例對象
- 在 Scala 中,是沒有 static 這個東西的,但是它也為我們提供了單例模式的實現方法,那就是使用關鍵字 object。
- Scala 中使用單例模式時,除了定義的類之外,還要定義一個同名的 object 對象,它和類的區(qū)別是,object對象不能帶參數。
- 當單例對象與某個類共享同一個名稱時,他被稱作是這個類的伴生對象:companion object。你必須在同一個源文件里定義類和它的伴生對象。類被稱為是這個單例對象的伴生類:companion class。
- 類和它的伴生對象可以互相訪問其私有成員
//私有構造方法
class Marker private(val color:String){
println("創(chuàng)建:" + this);
override def toString(): String = "顏色標記:"+ color //4:顏色標記:red
}
//伴生對象,能訪問類的私有屬性和方法
object Marker {
private val markers : Map[String, Marker] = Map(
"red" -> new Marker("red"), //1.創(chuàng)建顏色標記:red
"blue" -> new Marker("blue"), //2.創(chuàng)建顏色標記;blue
"green" -> new Marker("green") //3.創(chuàng)建顏色標記:green
)
def apply(color:String) = {
if(markers.contains(color)) markers(color) else null;
}
def getMarker(color:String) = {
if(markers.contains(color)) markers(color) else null; //5:顏色標記:blue
}
def main(args: Array[String]): Unit = {
println(Marker("red"));
//單例函數調用,省略了.(點)符號
println(Marker getMarker "blue");
}
}
運行結果:
14. Scala Trait(特征)
Scala Trait(特征) 相當于 Java 的接口,實際上它比接口還功能強大。
與接口不同的是,它還可以定義屬性和方法的實現。
一般情況下Scala的類只能夠繼承單一父類,但是如果是 Trait(特征) 的話就可以繼承多個,從結果來看就是實現了多重繼承。
- Trait(特征) 定義的方式與類類似,但它使用的關鍵字是 trait,如下所示:
trait Equal {
def isEqual(x:Any) : Boolean;
def isNotEqual(x:Any) : Boolean = !isEqual(x);
}
以上Trait(特征)由兩個方法組成:isEqual 和 isNotEqual。isEqual 方法沒有定義方法的實現,isNotEqual定義了方法的實現。子類繼承特征可以實現未被實現的方法。所以其實 Scala Trait(特征)更像 Java 的抽象類。
以下演示了特征的完整實例:
trait Equal {
def isEqual(x:Any) : Boolean;
def isNotEqual(x:Any) : Boolean = !isEqual(x);
}
class Point(xc:Int,yc:Int) extends Equal{
var x:Int = xc;
var y:Int = yc;
override def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == x
}
object Test{
def main(args: Array[String]): Unit = {
val p1 = new Point(2,3);
val p2 = new Point(2,4);
val p3 = new Point(3,3);
println(p1.isNotEqual(p2)) //false
println(p1.isNotEqual(p3)) //true
println(p1.isNotEqual(2)) //true
}
}
- 特征構造順序
特征也可以有構造器,由字段的初始化和其他特征體中的語句構成。這些語句在任何混入該特征的對象在構造時都會被執(zhí)行。
構造器的執(zhí)行順序:
- 調用超類的構造器;
- 特征構造器在超類構造器之后、類構造器之前執(zhí)行;
- 特征由左到右被構造;
- 每個特征當中,父特征先被構造;
- 如果多個特征共有一個父特征,父特征不會被重復構造
*所有特征被構造完畢,子類被構造。
15. Scala模式匹配
Scala 提供了強大的模式匹配機制,應用也非常廣泛。
一個模式匹配包含了一系列備選項,每個都開始于關鍵字 case。每個備選項都包含了一個模式及一到多個表達式。箭頭符號 => 隔開了模式和表達式。
示例:
object Test{
def main(args: Array[String]): Unit = {
println(matchText(3)); //many
}
def matchText(x : Int) : String = x match {
case 1 => "one";
case 2 => "two";
case _ => "many";
}
}
match 對應 Java 里的 switch,但是寫在選擇器表達式之后。即: 選擇器 match {備選項}。
match 表達式通過以代碼編寫的先后次序嘗試每個模式來完成計算,只要發(fā)現有一個匹配的case,剩下的case不會繼續(xù)匹配。
接下來我們來看一個不同數據類型的模式匹配:
object Test {
def main(args: Array[String]) {
println(matchTest("two"))
println(matchTest("test"))
println(matchTest(1))
println(matchTest(6))
}
def matchTest(x: Any): Any = x match {
case 1 => "one"
case "two" => 2
case y: Int => "scala.Int"
case _ => "many"
}
}
使用樣例類
使用了case關鍵字的類定義就是就是樣例類(case classes),樣例類是種特殊的類,經過優(yōu)化以用于模式匹配。
object Test {
def main(args: Array[String]) {
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)
for (person <- List(alice, bob, charlie)) {
person match {
case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) =>
println("Age: " + age + " year, name: " + name + "?")
}
}
}
// 樣例類
case class Person(name: String, age: Int)
}
在聲明樣例類時,下面的過程自動發(fā)生了:
- 構造器的每個參數都成為val,除非顯式被聲明為var,但是并不推薦這么做;
- 在伴生對象中提供了apply方法,所以可以不使用new關鍵字就可構建對象;
- 提供unapply方法使模式匹配可以工作;
- 生成toString、equals、hashCode和copy方法,除非顯示給出這些方法的定義。
16. Scala正則表達式
Scala 的正則表達式繼承了 Java 的語法規(guī)則
示例:
import scala.util.matching.Regex
object Test {
def main(args: Array[String]) {
val pattern = new Regex("(S|s)cala") // 首字母可以是大寫 S 或小寫 s
val str = "Scala is scalable and cool"
println((pattern findAllIn str).mkString(",")) // 使用逗號 , 連接返回結果
}
}
17. Scala異常處理
Scala 的異常處理和其它語言比如 Java 類似。
Scala 的方法可以通過拋出異常的方法的方式來終止相關代碼的運行,不必通過返回值。
- 拋出異常
Scala 拋出異常的方法和 Java一樣,使用 throw 方法,例如,拋出一個新的參數異常:
throw new IllegalArgumentException - 捕獲異常
異常捕捉的機制與其他語言中一樣,如果有異常發(fā)生,catch字句是按次序捕捉的。因此,在catch字句中,越具體的異常越要靠前,越普遍的異常越靠后。 如果拋出的異常不在catch字句中,該異常則無法處理,會被升級到調用者處。
捕捉異常的catch子句,語法與其他語言中不太一樣。在Scala里,借用了模式匹配的思想來做異常的匹配,因此,在catch的代碼里,是一系列case字句,如下例所示:
import java.io.{FileNotFoundException, FileReader, IOException}
object Test{
def main(args: Array[String]): Unit = {
try{
val f = new FileReader("input.txt");
}catch{
case ex : FileNotFoundException =>{
println("Missing file exception")
}
case ex : IOException =>{
println("IO exception")
}
}
}
}
18. Scala 提取器(Extractor)
apply方法:無需new操作就可創(chuàng)建對象。
unapply方法:是apply方法的反向操作,接受一個對象,然后從對象中提取值,提取的值通常是用來構造對象的值。
以下實例演示了郵件地址的提取器對象:
object Test{
def main(args: Array[String]): Unit = {
println("Apply方法:" + apply("Zara","gmail.com"));//Apply 方法 : Zara@gmail.com
println("unapply方法:" + unapply("Zara@gmail.com"));//Unapply 方法 : Some((Zara,gmail.com))
println("unapply方法:" + unapply("Zara Ali"));//Unapply 方法 : None
}
//注入方法(可選)
def apply(user:String, domain:String) ={
user + "@" + domain
}
//提取方法(必選)
def unapply(str: String): Option[(String,String)] = {
val parts = str split("@")
if(parts.length == 2){
Some(parts(0),parts(1))
}else{
None
}
}
}
以上對象定義了兩個方法: apply 和 unapply 方法。通過 apply 方法我們無需使用 new 操作就可以創(chuàng)建對象。所以你可以通過語句 Test("Zara", "gmail.com") 來構造一個字符串 "Zara@gmail.com"。
unapply方法算是apply方法的反向操作:unapply接受一個對象,然后從對象中提取值,提取的值通常是用來構造該對象的值。實例中我們使用 Unapply 方法從對象中提取用戶名和郵件地址的后綴。
- 提取器使用模式匹配
在我們實例化一個類的時,可以帶上0個或者多個的參數,編譯器在實例化的時會調用 apply 方法。我們可以在類和對象中都定義 apply 方法。
就像我們之前提到過的,unapply 用于提取我們指定查找的值,它與 apply 的操作相反。 當我們在提取器對象中使用 match 語句是,unapply 將自動執(zhí)行,如下所示:
object Test{
def main(args: Array[String]): Unit = {
val x = Test(5);//執(zhí)行apply
println(x)
x match{
//執(zhí)行unapply
case Test(num) => println(x + "是:" + num +"的兩倍")
case _ => println("無法計算")
}
}
//注入方法(可選)
def apply(x:Int) = x*2;
//提取方法(必選)
def unapply(z: Int): Option[Int] = if(z%2 == 0) Some(z/2) else None
}
19. Scala文件I/O
- 文件寫操作
Scala 進行文件寫操作,直接用的都是 java中 的 I/O 類 (java.io.File)
import java.io._
object Test{
def main(args: Array[String]): Unit = {
val writer = new PrintWriter(new File("test.txt"))
writer.write("Scala教程");
writer.close();
}
}
- 從屏幕上讀取用戶操作
import scala.io.StdIn
object Test{
def main(args: Array[String]): Unit = {
print("請輸入百度地址:")
val line = StdIn.readLine();
println("你輸入的是: " + line)
}
}
- 從文件上讀取內容
從文件讀取內容非常簡單。我們可以使用 Scala 的 Source 類及伴生對象來讀取文件。以下實例演示了從 "test.txt"(之前已創(chuàng)建過) 文件中讀取內容:
import scala.io.Source
object Test{
def main(args: Array[String]): Unit = {
println("文件內容是:")
Source.fromFile("test.txt").foreach{
print;
}
}
}
參考:https://www.cnblogs.com/ahu-lichang/p/7207847.html?utm_source=itdadao&utm_medium=referral