scala基礎:
hello world:
- 寫scala可運行文件的注意事項
- 1、如果一個scala文件要運行,class要改成object
- 2、如果是class,就僅單純代表一個類,如果是object代表的是單例對象
- 3、scala語法中,一句話結束不需要加分號
- 4、scala文件中,可以無縫使用java中的類和方法
object HelloWorld {def main(args: Array[String]): Unit = {// 輸出一句hello worldprintln("hello world")// java語言的輸出一句話System.out.println("hello world")}
}
變量、常量
/*** 變量:在程序的運行過程中,其值可以發生改變的量* 在scala中定義一個變量,需要使用一個關鍵詞:var*常量: 定義一個常數,使用關鍵字:var* 注意:* 1、變量一旦定義,它的類型就確定,可以不用手動指定類型,根據賦的值自動推斷出類型* 2、也可以手動的指定變量的數據類型,完整的寫法:var 變量名:數據類型 = 值** scala中的數據類型和java的數據類型對應關系(Byte->Double 按所占字節數的大小,從小到大進行排序):* java: scala:* byte Byte* short Short* int Int* long Long* float Float* double Double* boolean Boolean* char Char*/
// var定義一個變量var a1 = 100println(a1)//獲取變量的類型println(a1.getClass)// 更改a1的值a1 = 200println(a1)var a2: Int = 10println(a2.getClass)val a3: Int = 100println(a3)// val 定義常量,若是修改其值會報錯
// a3 = 200// * : 為一個函數,底層通過StringBuilder來實現字符的鏈接println("=" * 50)
字符串
/*** scala中字符串、及其函數的使用* 字符串:由若該字符串組成的序列*/
// 可以使用雙引號構建字符串
var s1: String = "這是一個字符串"
println(s1)// 使用""" """" 構建一個長字符串
var sql: String ="""|這是一個長字符串|真的很長|注意了!!!|""".stripMargin
println(sql)// String類和Java是一個共同的字符串類,String類中的功能在scala中正常使用var s3 = "hello,world,java,hadoop,scala"
val arr1: Array[String] = s3.split(",")
// scala中的數組下標也是從0開始的,不過取的時候要使用arr1(0)
println(arr1(0))
println(arr1(1))
println(arr1(2))/*** scala中字符串的拼接:* 1、使用 + 進行拼接,不過這種方式很消耗性能* 2、使用StringBuilder* 3、使用scala的特有函數mkString,前提條件是:有一組可拼接的序列* 4、使用scala特有的字符串傳遞方式 s"{變量}” (類似于python語言) 底層就是使用StringBuilder方式拼接的*/
var q1: String = "hello"
var q2: String = "hello"
var q3: String = "hello"
var res1: String = q1 + "," + q2 + "," + q3
println(res1)var res2: StringBuilder = new StringBuilder()
res2.append(q1).append(",").append(q2).append(",").append(q3)
println(res2)var res3: String = arr1.mkString(",")
println(res3)// 使用s"${}", 功能強大可以在括號中調用函數
var res4: String = s"${q1.toUpperCase},${q2},${q3}"
println(res4)
運算符
/*** 運算符*/
var x: Int = 3
var y: Int = 4println(x + y)
println(x - y)
println(x * y)
//此處的 / 為整除,若想讓其取小數,可以讓兩個數中的其中一個變成一個浮點數
println(x / y)
println(x * 1.0 / y)
println(x % y)
循環語句
/*** 循環語句:* 注:* 1、在scala語言中,沒有++或--, 如 i++ 、 i--* 2、在scala語言中,不存在和java一樣的普通for循環* 3、scala中的循環的寫法不太一樣*/var i: Int = 0
while (i < arr2.length){println(arr2(i))
}// 1 to 10 : 相當于閉區間的1到10
for (e <- 1to 10){println(e)
}for(e <- 1 until 10){println(e)
}
控制語句
/*** 控制語句* 注:在scala中沒有break、continue關鍵字* 要想使用break得導包:import scala.util.control.Breaks.break*///TODO 在break后,程序的執行結束,如若想繼續執行,那么需要再加上一個breakablebreakable{for (e <- 1 to 10) {if (e == 5) {//TODO:底層為一個異常拋出, def break(): Nothing = { throw breakException }break;}println(e)}}println("太牛了!")
}
IO流
def main(args: Array[String]): Unit = {//讀取一個文件內容//使用java的方式讀取文件, 使用帶緩沖區的字符輸入流val br: BufferedReader = new BufferedReader(new FileReader("scala/data/words.txt"))var line:String = br.readLine()while (line!=null){println(line)line = br.readLine()}//scala中的讀取文件的方式//Source.fromFil 底層是使用了字節輸入流讀取數據FileInputStreamval bs: BufferedSource = Source.fromFile("scala/data/words.txt")// getLines();返回的是一個迭代器對象, 使用迭代器的hasNext()、next() 方法進行數據的輸出val lineIterator: Iterator[String] = bs.getLines()while (lineIterator.hasNext){val s: String = lineIterator.next()println(s)}// 既然返回的是一個迭代器,那么就可以使用for循環來進行輸出for (e <- bs.getLines()) {println(e)}//java寫文件/*** FileWriter對象被用作參數來創建一個BufferedWriter對象。* 這樣,就可以通過BufferedWriter來寫入字符,而實際的寫入操作(包括可能的緩沖)將由BufferedWriter處理。*/val bw = new BufferedWriter(new FileWriter("scala/data/words2.txt"))bw.write("寫入數據!")// newLine()方法用于寫入一個行分隔符bw.newLine()bw.write("太棒了!")//flush()方法用于將緩沖區中的數據強制寫入到底層輸出流(如FileWriter)中,并清空緩沖區。bw.flush()//TODO 純scala中沒有寫文件的方式!!}
異常拋出(與java中很像)
手動拋出異常:
val sc = new Scanner(System.in)
print("輸入除數:")
val cs: Int = sc.nextInt()
if(cs!=0){println(10/cs)
}else{throw new ArithmeticException("您輸入的除數是0")
}
使用try、catch捕獲異常
def main(args: Array[String]): Unit = {/*** scala中的異常和java的很像*/try {println(10/2)val arr1: Array[Int] = Array(1, 2, 3, 4, 5)println(arr1(2))val br: BufferedReader = new BufferedReader(new FileReader("scala/data/words888.txt"))val sc = new Scanner(System.in)print("輸入除數:")val cs: Int = sc.nextInt()println(10/cs)// 異常被捕獲后,后續代碼都可以運行}catch{//類似于sql語句中case when// 使用case來選擇拋出的異常case e:ArithmeticException=>println("除0異常")e.printStackTrace()case e:ArrayIndexOutOfBoundsException=>println("數組越界異常")// TODO _ : 表示所有的異常都可以拋出,相當于Exceptioncase _ =>println("出現異常")}finally {//TODO 用于確保無論是否發生異常,都會執行一段代碼。// 今后finally中的處理大部分情況下都與釋放資源有關println("這是finally代碼塊")}println("hello world")
}
scala中的函數
/*** def: 定義函數或者方法的關鍵字* main: 是函數或者方法的名字,符合標識符的命名規則* args: 函數形參的名字* Array[String]: 參數的數據類型是一個元素為字符串的數組* =: 后面跟著函數體(與Java中不同之處)* Unit: 等同于java中的void 表示無返回值的意思**形式:* def main(args: Array[String]): Unit = {** }** 在不同的地方定義,稱呼不一樣* 函數:在object中定義的叫做函數* 方法:在class中定義的叫做方法*/object Demo5Function {def main(args: Array[String]): Unit = {//調用函數val res1: Int = add(3, 4)println(res1)// scala中的函數可以嵌套定義,函數中可以再定義函數def plus(x: Int, y: Int): Int = {return x + y}//調用必須在定義之后val res2: Int = plus(10, 20)println(res2)// 函數無法成功調用
// val res3: Int = add2(11, 22)
// println(res3)val d1: Demo1 = new Demo1()val res4: Int = d1.add2(11, 22)println(res4)//調用形式1:object中的函數可以使用類名調用,類似于靜態一樣val res5: Int = Demo5Function.add(100, 200)println(res5)//調用形式2:object中的函數調用時,可以省略類名val res6: Int = add(200, 300)println(res6)val res7: Int = fun1("1000")println(res7)//TODO 如果方法調用的函數只有一個參數的時候,可以將.和小括號用空格代替調用val res9: Int = Demo5Function.fun1("1000")val res8: Int = Demo5Function fun1 "1000" // "=" * 50 -> "=".*(50)println(res8)//TODO 如果定義的時候,沒有小括號,調用的時候,就不需要加小括號(無需傳入參數)show}//定義格式1:如果函數有返回值,且最后一句話作為返回值的話,return關鍵字可以不寫def add3(a1: Int, b1: Int): Int = {a1 + b1}//定義格式2:如果函數體中只有一句實現,那么大括號也可以不寫def add4(a1: Int, b1: Int): Int = a1 + b1//定義格式3:如果函數沒有參數的時候,小括號省略不寫def show= println("好好學習,天天向上!")//需求1:定義一個求兩個數之和的函數,返回結果def add(a1: Int, b1: Int): Int = {return a1 + b1}def fun1(s:String): Int = {return s.toInt}}//TODO 函數或者方法必須定義在class或者object中,否則將會報錯,無法進行編譯
//def add2(a1: Int, b1: Int): Int = {
// return a1 + b1
//}class Demo1{//這里叫方法,將來調用時需要創建該類的對象才可以調用def add2(a1: Int, b1: Int): Int = {return a1 + b1}
}
遞歸調用
/*** scala中的函數也可以遞歸* 方法定義時,自身調用自身的現象** 條件:要有出口(停止遞歸調用條件),不然就是死遞歸*/
object Demo6Function {def main(args: Array[String]): Unit = {//求階乘 5!val res1: Int = factorial(5)println(s"5的階乘是$res1")println(s"5的階乘是${Demo6Function factorial 5}")}def factorial(number: Int): Int = {if (number == 1) {1} else {number * factorial(number - 1)}}}
scala中定義class類
object Demo7Class {def main(args: Array[String]): Unit = {// val s1: Student = new Student()// val s1: Student = new Student("張三",18)val s2: Student = new Student("張三", 18, "男")println(s2)//如果調用的是一個類的無參構造方法,new的時候小括號可以不用寫val s3: Student2 = new Student2s3.fun1()//也可以使用多態的方式創建對象val s4:Object = new Student("張三111", 19, "男")
// s4.fun1()println(s4.toString)}
}/*** 可以在scala程序定義類* 類:構造方法 成員方法 成員變量** 構造方法:* 1、在scala中構造方法的編寫和在java中不太一樣,類所擁有的大括號中都是構造代碼塊的內容* 2、默認情況下,每一個類都應該提供一個無參的構造方法* 3、構造方法可以有許多*/
class Student(name: String, age: Int) {/*** 定義成員變量*/val _name: String = nameval _age: Int = age// _: 這個下劃線,就表示將來不傳值時,會賦予其默認值。String的默認值是一個特殊的值,即nullvar _gender: String = _/*** 構造方法也可以寫多個*/// TODO def this () :為重載的構造器,有著不同的參數列表,// 在創建類的對象時,若傳遞三個參數,則會使用該構造方法進行初始化對象def this(name: String, age: Int, gender: String) {/*** this():* 用于在輔助構造器中調用主構造器或其他輔助構造器,* 以確保對象被正確初始化。需要注意的是,this(...)調用必須是構造器體中的第一條語句。*/this(name: String, age: Int)_gender = gender}// println("好好學習,天天向上!")/*** 也可以重寫方法* 此處定義的類的父類都是Object,重寫繼承自父類的toString方法*/override def toString: String = {// 使用s"${}"的形式會報錯"姓名:" + _name + ", 年齡:" + _age + ", 性別:" + _gender}// override def toString: String = super.toString
}class Student2{def fun1()={println("666")}
}
樣例類
/*** scala提供了一個非常好用的功能:樣例類* 較少用戶創建類所編寫代碼量,只需要定義成員變量即可,自動擴充成員變量,構造方法,重寫toString方法*/
object Demo8CaseClass {def main(args: Array[String]): Unit = {val t1 = new Teacher("小虎", 16, "學習")println(t1)println(t1.name)println(t1.age)println(t1.like)t1.like = "敲代碼"println(t1)}
}/*** 樣例類中的成員變量,編譯后默認是被jvm添加了final關鍵字,用戶是改變不了的* 對于scala來說,默認是被val修飾的* 如果將來想要被改變,定義的時候需要使用var進行修飾*/
case class Teacher(name:String,age:Int,var like:String)
伴生對象(apply方法)
object Demo9Apply {def main(args: Array[String]): Unit = {val b: Book1 = new Book1()b.apply() // 定義在class中是一個普通的方法// TODO: 若定義在object中,那么可以直接用Book("中華上下五千年", 999)的形式來調用這個方法val b1: Book = Book("中華上下五千年", 999)println(b1)}
}class Book1 {def apply(): Unit = {println("哈哈哈")}
}// TODO object Book 為 class Book的伴生對象
object Book {def apply(name:String,price:Int): Book = {new Book(name,price)}
}class Book(name: String, price: Int) {val _name: String = nameval _price: Int = priceoverride def toString: String = "書名:" + _name + ", 價格:" + _price
}
scala面向函數式編程
/*** scala中的函數式編程** 面向對象編程:將對象當作參數一樣傳來傳去* 1、對象可以當作方法參數傳遞* 2、對象也可以當作方法的返回值返回* 當看到類,抽象類,接口的時候,今后無論是參數類型還是返回值類型,都需要提供對應的實現類對象** 面向函數式編程:將函數當作參數一樣傳來傳去* 1、函數A當作函數B的參數進行傳遞* 2、函數A當作函數B的返回值返回** 在scala中,將函數也當作一個對象,對象就有類型* 函數在scala也有類型的說法* 函數的類型的形式為:* 參數類型=>返回值類型**/
將函數當作對象,賦值給類型是函數類型的變量
//是一個參數為字符串類型,返回值是整數類型的函數def fun1(s: String): Int = {s.toInt + 1000}val res1: Int = fun1("1000")println(res1)//定義變量的方式,定義一個函數//將函數當作對象,賦值給類型是函數類型的變量,將來可以直接通過變量調用函數val fun2: String => Int = fun1val res2: Int = fun2("2000")println(res2)/*** 函數A作為函數B的參數定義** 本質上是將函數A的處理邏輯主體傳給了函數B,在函數B中使用這個處理邏輯*/
// show1 show2 相當于函數A
// fun1 相當于函數B//定義def fun1(f: String => Int): Int = {val a1: Int = f("1000")a1 + 3000}def show1(s:String): Int = {s.toInt}//調用val res1: Int = fun1(show1)println(res1)def show2(s: String): Int = {s.toInt+11111}val res2: Int = fun1(show2)println(res2)//定義一個函數fun1, 函數的參數列表中,既有正常的類型參數,也有函數類型的參數def fun1(s: String, f: String => Int): Int = {val a1: Int = f(s)a1 + 1000}def show1(s: String): Int = {s.toInt}def show2(s: String): Int = {s.toInt + 1111}//.....val res1: Int = fun1("2000", show2)println(res1)//使用lambda表達式改寫函數作為參數傳遞的調用形式:(s: String) => s.toIntfun1("2000", (s: String) => s.toInt)fun1("2000", (s: String) => s.toInt+1000)//在scala中,數據類型可以自動類型推斷fun1("2000", s => s.toInt+1000)//如果當作參數的函數的參數只在函數主體使用了一次,那么可以使用_代替fun1("2000", _.toInt+1000)val res2: Int = fun1("2000", _.toInt+1000)println(res2)
函數當作參數傳遞的應用
object Demo11Fun {def main(args: Array[String]): Unit = {val arr1: Array[Int] = Array(11, 22, 33, 44, 55)// for循環輸出數組for (e <- arr1) {println(e)}// 定義一個函數def fun1(i: Int): Unit = {println(i*2)}//def foreach[U](f: A => U): Unit//foreach函數需要一個參數,它和數組元素一樣的類型,返回值是Unit的函數//foreach函數的主要作用是將調用該方法的序列中的元素,依次取出并傳遞給傳入的函數進行處理arr1.foreach(fun1)// scala自帶的一個函數def println(x: Any) = Console.println(x)// Any可以接收任意的數據類型元素arr1.foreach(println)}
}
函數當作返回值返回
//定義返回值是函數的函數方式1:def fun1(s1: String): String => Int = {def show(s: String): Int = {s.toInt + s1.toInt}show}val resFun1: String => Int = fun1("1")val res1: Int = resFun1("1000")println(res1)
//定義方式2(是方式1的簡化寫法):/*** 方式2這種將參數分開定義,今后調用時可以分開傳遞,這種做法,在scala中叫做函數柯里化** 面試題:什么是函數柯里化?* 1、本身是一個數學界的一個名詞,本意是原來一次傳遞多個參數,現在被改成了可以分開傳遞的形式,這種做法叫做柯里化* 2、在scala中體現柯里化,指的是函數的返回值也是一個函數,將來調用時參數可以分開傳遞。* 3、提高了程序的靈活性和代碼復用性* 4、在scala中也可以通過偏函數實現參數分開傳遞的功能*/
def fun1(s1: String)(s: String): Int = {s.toInt + s1.toInt
}//調用函數的返回值是函數的方式1:
val resFun1: String => Int = fun1("1")
val r1: Int = resFun1("11")
println(r1)
val r2: Int = resFun1("12")
println(r2)
val r3: Int = resFun1("13")
println(r3)//調用方式2:val res2: Int = fun1("1")("1000")println(res2)def function1(s1: String, s2: String): Int = {s1.toInt + s2.toInt
}val res1: Int = function1("1", "1000")println(res1)
/*** 偏函數*/
//TODO 將第二個參數用 _ 代替,則會返回一個函數(由底層代碼進行操作)
val f1: String => Int = function1("1", _)
val res1: Int = f1("1000")
val res2: Int = f1("2000")
val res3: Int = f1("3000")
println(s"res1:$res1,res2:$res2,res3:$res3")
集合
ArrayList
package com.shujia.jichuimport java.utilobject Demo13ArrayList {def main(args: Array[String]): Unit = {val list1: util.ArrayList[Int] = new util.ArrayList[Int]()list1.add(11)list1.add(123)list1.add(22)list1.add(31)list1.add(17)println(list1)println("=" * 50)//scala中的for循環,只能遍歷scala中的序列,無法遍歷java的序列// for (e <- list1) {//// }var i = 0while (i < list1.size()) {println(list1.get(i))i += 1}}
}
- scala中的集合:
- List: 元素有序,且可以發生重復,長度固定的
- Set: 元素無序,且唯一,長度固定的
- Map: 元素是鍵值對的形式,鍵是唯一的
- Tuple: 元組,長度是固定的,每個元素的數據類型可以不一樣
List
//創建一個scala中的List集合
//創建了一個空集合
val list1: List[Nothing] = List()
val list2: List[Int] = List(34, 11, 22, 11, 33, 44, 55, 22, 75, 987, 1, 12, 34, 66, 77)println(list2)
//獲取List集合的長度
println(list2.size)
println(list2.length)
println("=" * 50)
//可以直接通過索引下標獲取元素
println(list2(0))
println(list2(1))
println(list2(2))
println("=" * 50)
//scala推薦獲取第一個元素的方式是調用head函數(scala更希望使用這種方式來獲取第一個元素的值)
println(list2.head)
println(list2.last)
//根據指定的分隔符拼接元素
println(list2.mkString("|"))
// 34|11|22|11|33|44|55|22|75|987|1|12|34|66|77
println("=" * 50)
val resList1: List[Int] = list2.reverse //返回一個新的所有元素反轉的集合
println(s"list2:$list2")
println(s"resList1:$resList1")
println("=" * 50)
val resList2: List[Int] = list2.distinct //返回一個新的沒有重復元素的集合
println(s"list2:$list2")
println(s"resList2:$resList2")
println("=" * 50)
val resList3: List[Int] = list2.tail // 除去第一個,其余的元素返回一個新的集合
println(s"list2:$list2")
println(s"resList3:$resList3")
println("=" * 50)
val resList4: List[Int] = list2.take(5) // 從左向右取指定數量的元素
println(s"list2:$list2")
println(s"resList4:$resList4")
println("=" * 50)
val resList5: List[Int] = list2.takeRight(5) //取右邊的幾個(取的順序為從左向右),組成新的集合
println(s"list2:$list2")
println(s"resList5:$resList5")
println("=" * 50)
//從第一個判斷取數據,直到不符合條件停止
val resList10: List[Int] = list2.takeWhile((e: Int) => e % 2 == 0)
println(s"list2:$list2")
println(s"resList10:$resList10")
// resList10:List(34)
println("*********************" * 5)
val res1: Int = list2.sum // 元素必須是數值,sum求和
println(s"集合中的元素和為:$res1")
println("=" * 50)
val res2: Int = list2.max
println(s"集合中的元素最大值為:$res2")
println("=" * 50)//集合的遍歷
for (e <- list2) {println(e)
}
println("=" * 50)
高階函數
- 高階函數:
- foreach: 依次取出元素,進行后面函數邏輯,沒有返回值
- map: 依次取出元素,進行后面函數邏輯,有返回值,返回新的集合
- filter: 所有數據中取出符合條件的元素
- sortBy/sortWith: 排序
- flatMap: 扁平化
- groupBy: 分組,結果是一個map集合
foreach
- foreach: 將集合中的元素依次取出傳入到后面的函數中
- 注意:沒有返回值的,要么就輸出,要么就其他方式處理掉了
//def foreach[U](f: A => U)
// list2.foreach((e: Int) => println(e))
// list2.foreach(println)
//需求1:使用foreach求出集合中偶數的和
var ouSum = 0
var jiSum = 0
list2.foreach((e: Int) => {if (e % 2 == 0) {ouSum += e} else {jiSum += e}
})
println(s"集合中偶數之和為:$ouSum")
println(s"集合中奇數之和為:$jiSum")
println("=" * 50)
map
- 高階函數:
- map: 依次處理每一個元素,得到一個新的結果,返回到一個新的集合中
val list3: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
//需求2:將集合中的每一個元素*2
val resList6: List[Int] = list3.map((e: Int) => e * 2)
println(s"list3:$list3")
println(s"resList6:$resList6")
filter
保留符合條件的元素
println("=" * 50)
val list4: List[Int] = List(4, 7, 9, 10, 12, 11, 14, 9, 7)
val resList7: List[Int] = list4.filter((e: Int) => e % 2 == 0)
println(s"list4:$list4")
println(s"resList7:$resList7")
sortBy、sortWith
- sortBy: 排序
- sortWith: 兩個數之間的關系排序
println("=" * 50)
// -e : 表示為降序排序
val resList8: List[Int] = list4.sortBy((e: Int) => -e)
println(s"list4:$list4")
println(s"resList8:$resList8")
// 相鄰元素之間兩兩比較,遞減排序
val resList9: List[Int] = list4.sortWith((x: Int, y: Int) => x > y)
println(s"list4:$list4")
println(s"resList9:$resList9")
flatMap
- flatMap: 扁平化
println("=" * 50)
val list5: List[String] = List("hello|world|java", "hello|hadoop|flink", "scala|spark|hadoop")
val resTmp1: List[String] = list5.flatMap((e: String) => e.split("\\|"))
resTmp1.foreach(println)
/*** hello* world* java* hello* hadoop* flink* scala* spark* hadoop*/
groupBy
- groupBy: 分組
val list6: List[String] = List("hello", "world", "java", "hadoop", "flink", "java", "hadoop", "flink", "flink", "java", "hadoop", "flink", "java", "hadoop", "hello", "world", "java", "hadoop", "hello", "world", "java", "hadoop")
val map: Map[String, List[String]] = list6.groupBy((e: String) => e)
for (e <- map) {println(e)
}
set集合
def main(args: Array[String]): Unit = {// val set1: Set[Int] = Set(11, 22, 33, 44)/*** set集合:scala中的Set集合也是不可變的,除了排序相關的函數以外,List集合有的高階函數,Set集合也有*/val set1: Set[Int] = Set(1, 4, 3, 6, 5)val set2: Set[Int] = Set(3, 6, 5, 7, 8)println(s"set1: ${set1}")println(s"set2: ${set2}")println("=" * 50)//求交集
// val resSet1: Set[Int] = set1.&(set2)
// val resSet1: Set[Int] = set1 & set2val resSet1: Set[Int] = set1.intersect(set2)println(s"set1: ${set1}")println(s"set2: ${set2}")println(s"交集: ${resSet1}")println("=" * 50)//求并集// val resSet2: Set[Int] = set1.|(set2)val resSet2: Set[Int] = set1 | set2println(s"set1: ${set1}")println(s"set2: ${set2}")println(s"并集: ${resSet2}")println("=" * 50)//求差集// val resSet3: Set[Int] = set1.&~(set2)val resSet3: Set[Int] = set1 &~ set2println(s"set1: ${set1}")println(s"set2: ${set2}")println(s"差集: ${resSet3}")println("=" * 50)/*** Set集合和List集合能不能互相轉換?* 可以的*/val list1: List[Int] = List(11, 22, 33, 44, 55, 11, 22, 44, 88, 33, 44, 99, 11, 22, 55)//List->Setval resSet4: Set[Int] = list1.toSetprintln(s"list1:${list1}")println(s"resSet4:${resSet4}")println("=" * 50)//Set->Listval list2: List[Int] = resSet4.toList.sortBy((e:Int)=>e)println(s"list1:${list1}")println(s"resSet4:${resSet4}")println(s"list2:${list2}")}
Mutable下的可變的集合
import scala.collection.mutable
import scala.collection.mutable.ListBufferobject Demo16Mutable {def main(args: Array[String]): Unit = {/*** 通過觀察api發現,不可變的集合是屬于scala.collection.immutable包下的* 如果將來想要使用可變的集合,就要去scala.collection.mutable包下尋找*///創建一個可變的List集合val listBuffer1: ListBuffer[Int] = new ListBuffer[Int]println(listBuffer1)listBuffer1.+=(11)listBuffer1.+=(22)listBuffer1.+=(33)listBuffer1.+=(11)listBuffer1.+=(55)listBuffer1.+=(22)listBuffer1.+=(33)listBuffer1.+=(66)listBuffer1.+=(33)println(listBuffer1)println("=" * 50)//獲取元素println(listBuffer1(2))println(listBuffer1.head)println(listBuffer1.last)/*** 這里的可變List集合,上午說的功能函數,這里都可以調用*/println("=" * 50)//刪除元素//ListBuffer(11, 22, 33, 11, 55, 22, 33, 66, 33)listBuffer1.-=(33) //從左向右找元素,只會刪除第一次找到的println(listBuffer1)println("=" * 50)//批量添加元素listBuffer1.+=(100,220,300,400)println(listBuffer1)println("=" * 50)val list1: List[Int] = List(99, 88, 77)listBuffer1.++=(list1)println(listBuffer1)/*** 可變的Set集合*/val hashSet1: mutable.HashSet[Int] = new mutable.HashSet[Int]()val set1: hashSet1.type = hashSet1.+=(1, 2, 3, 4, 5, 7, 1, 2, 3, 1, 6, 5)println(set1)}
}
元組
/*** 大小,值是固定的,根據創建的類來定,每個元素的數據類型可以是不一樣,最高可以創建存儲22個元素的元組*/
object Demo17Tuple {def main(args: Array[String]): Unit = {// 有幾個數值就是幾元組val t1: (Int, String, String, Int, String) = Tuple5(1001, "張三", "男", 17, "學習")println("=" * 50)val s2: Student1 = new Student1(1002, "李四", 18, "看劇")val t2: (Int, Student1) = Tuple2(1002, s2)println(t2._2.name)}
}case class Student1(id: Int, name: String, age: Int, like: String)
Map集合
object Demo18Map {def main(args: Array[String]): Unit = {//創建Map集合//鍵是唯一的,鍵一樣的時候,值會被覆蓋val map1: Map[Int, String] = Map((1001, "張三"), (1002, "李四"), (1003, "王五"), (1001, "趙六"), 1005 -> "易政")println(map1)println("=" * 50)//可以根據鍵獲取值// println(map1(1006)) // 小括號獲取值,鍵不存在報錯// println(map1.get(1006)) // get函數獲取,鍵不存在,返回Noneprintln(map1.getOrElse(1006, 0)) //根據鍵獲取值,若鍵不存在,返回提供的默認值,默認值的類型可以是任意數據類型println("=" * 50)val keys: Iterable[Int] = map1.keys // 獲取所有的鍵,組成一個迭代器for (e <- keys) {println(e)}println("=" * 50)val values: Iterable[String] = map1.values // 獲取所有的值,組成一個迭代器for (e <- values) {println(e)}println("=" * 50)//遍歷Map集合第一種方式,先獲取所有的鍵,根據鍵獲取每個值val keys2: Iterable[Int] = map1.keys // 獲取所有的鍵,組成一個迭代器for (e <- keys2) {val v: Any = map1.getOrElse(e, 0)println(s"鍵:${e}, 值:${v}")}println("=" * 50)//遍歷Map集合第二種方式,先獲取所有的鍵,根據鍵獲取每個值for (kv <- map1) { // 直接遍歷map集合,得到每一個鍵值對組成的元組println(s"鍵:${kv._1}, 值:${kv._2}")}println("=" * 50)//遍歷Map集合第三種方式,先獲取所有的鍵,根據鍵獲取每個值map1.foreach((kv: (Int, String)) => println(s"鍵:${kv._1}, 值:${kv._2}"))}
}
wordcount案例
import scala.io.{BufferedSource, Source}object Demo19WordCount {def main(args: Array[String]): Unit = {//1、讀取數據文件,將每一行數據封裝成集合的元素val lineList: List[String] = Source.fromFile("scala/data/words.txt").getLines().toListprintln(lineList)//2、將每一行數據按照|切分,并且進行扁平化val wordsList: List[String] = lineList.flatMap((line: String) => line.split("\\|"))println(wordsList)//3、根據元素進行分組val wordKV: Map[String, List[String]] = wordsList.groupBy((e: String) => e)println(wordKV)/*** List((world,8), (java,11),...)*/val wordCount: Map[String, Int] = wordKV.map((kv: (String, List[String])) => {val word: String = kv._1val count: Int = kv._2.size(word, count)})println("="*50)val resultList: List[(String, Int)] = wordCount.toListresultList.foreach(println)println("="*50)/*** 使用鏈式調用的方式簡寫*/Source.fromFile("scala/data/words.txt").getLines().toList.flatMap((line:String)=>line.split("\\|")).groupBy((e:String)=>e).map((kv: (String, List[String])) => {val word: String = kv._1val count: Int = kv._2.size(word, count)}).toList.foreach(println)println("=" * 50)/*** 使用鏈式調用的方式簡寫*/Source.fromFile("scala/data/words.txt").getLines().toList.flatMap(_.split("\\|")).groupBy((e:String)=>e).map((kv: (String, List[String])) => (kv._1, kv._2.size)).toList.foreach(println)}
}
JDBC
import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}/*** jdbc的鏈接步驟* 1、注冊驅動* 2、創建數據庫鏈接對象* 3、創建數據操作對象* 4、執行sql語句* 5、如果第4步是查詢的話,分析查詢結果* 6、釋放資源*/object Demo20JDBC {def main(args: Array[String]): Unit = {//1、注冊驅動(若是8及其以后的版本需要mysql.cg.jdbc)Class.forName("com.mysql.jdbc.Driver")//2、創建數據庫鏈接對象//jdbc:數據庫名://host:port/數據庫?xxx=xxx&xxx=xxxval conn: Connection = DriverManager.getConnection("jdbc:mysql://192.168.128.100:3306/studentdb?useUnicode=true&characterEncoding=UTF-8&useSSL=false", "root", "123456")//3、創建數據操作對象val preparedStatement: PreparedStatement = conn.prepareStatement("select student_id,cource_id,score from score where score > ?")//4、執行sql語句
// preparedStatement.setInt(1,23)// 傳入參數防止sql注入preparedStatement.setInt(1, 60)val resultSet: ResultSet = preparedStatement.executeQuery()//5、如果第4步是查詢的話,分析查詢結果while (resultSet.next()){val student_id: String = resultSet.getString("student_id")val cource_id: String = resultSet.getString("cource_id")val score: Int = resultSet.getInt("score")println(s"學號:$student_id, 課程號:$cource_id, 分數:$score")}//6、釋放資源conn.close()}
}
Json
import com.alibaba.fastjson.{JSON, JSONArray, JSONObject}import scala.io.Sourceobject Demo21Json {def main(args: Array[String]): Unit = {val lineList: List[String] = Source.fromFile("scala/data/stu.json").getLines().toListval jsonStr: String = lineList.mkString("\n")println(jsonStr)//使用fastjson包中的JSON類,將一個字符串轉成json對象//轉成json對象之后,可以通過鍵獲取值
// parseObject 將整體轉成一個json格式數據val jsonObj1: JSONObject = JSON.parseObject(jsonStr)println(jsonObj1)val s1: String = jsonObj1.getString("student_list")println(s1)//parseArray將一個"[{},{}]"變成一個元素是json對象的數組val jSONArray: JSONArray = JSON.parseArray(s1)var i = 0while (i < jSONArray.size()) {// getJSONObject(i): 獲取數組中的第 i 個json對象val obj1: JSONObject = jSONArray.getJSONObject(i)val name: String = obj1.getString("name")val like: String = obj1.getString("like")println(s"${name}的愛好是${like}")i += 1}}}
Java與scala中的集合的相互轉換
import java.utilobject Demo22Scala2Java {def main(args: Array[String]): Unit = {//創建一個java中的集合val array1: util.ArrayList[Int] = new util.ArrayList[Int]()array1.add(11)array1.add(22)array1.add(33)array1.add(66)array1.add(55)array1.add(44)println(array1)/*** 將java中的集合轉成scala中的集合** java中的集合本來是沒有轉換scala的功能,需要導入隱式轉換* scala中的導包,可以在任意地方**/import scala.collection.JavaConverters._val list1: List[Int] = array1.asScala.toListprintln(list1)/*** scala中的集合轉java的集合*/val list2: util.List[Int] = list1.asJavaprintln(list2)}
}
Match
import java.util.Scanner
import scala.io.Sourceobject Demo23Match {def main(args: Array[String]): Unit = {/*** 模式匹配,就可以幫助我們開發的時候,減少代碼量,讓邏輯看起來更加清晰,以及可以避免一些異常* 語法:* 表達式 match {* case 值|[變量名:類型]|元組|數組|對象=>* 匹配成功執行的語句* case xxx=>* xxx* _ xxx=>* xxx* }** 模式匹配中,如果沒有對應的匹配,那么就報錯!!!*//*** 可以匹配變量值*/var i: Int = 100i match {case 20 => println("該值是20")case 50 => println("該值是50")// case 100=>println("該值是100")case _ => println("其他值")}/*** 匹配數據類型*/var flag1: Any = trueflag1 match {case _: Int => println("是Int類型")case _: Boolean => println("是boolean類型")}/*** 匹配元組* 元素的數量與類型都得一一對應*/val t1: (Int, String, Int) = Tuple3(1001, "張三", 18)t1 match {case (a1: Int, b1: String, c1: Int) =>println(s"學號:$a1, 姓名:$b1, 年齡:$c1")}/*** 匹配數組* 可以用來做數據封裝*/val array: Array[Any] = Array(1001, "李四", "男", 18, "理科一班")array match {case Array(id: Int, name: String, gender: String, age: Int, clazz: String) =>println(s"學號:$id, 姓名:$name, 性別:$gender, 年齡:$age, 班級:$clazz")}/*** 模式匹配的應用1:避免異常**/val map1: Map[Int, String] = Map((1001, "張三"), (1002, "李四"))val res1: Option[String] = map1.get(1001) // Some("張三")println(res1.get) // 返回的數值為Option[String]類型
// val res1: Option[String] = map1.get(1003)
// println(res1.get)val sc: Scanner = new Scanner(System.in)println("請輸入要查詢的鍵:")val key: Int = sc.nextInt()map1.get(key) match {case Some(a: Any) => println(s"${key}鍵對應的值為$a")case None => println(s"${key}鍵不存在!")}println("=" * 50)/*** 模式匹配的應用2:簡化代碼**/val stuList: List[String] = Source.fromFile("scala/data/students.txt").getLines().toListval stuArrayList: List[Array[String]] = stuList.map((line: String) => line.split(","))stuArrayList.map((e:Array[String])=>{val id: String = e(0)val name: String = e(1)val age: String = e(2)val gender: String = e(3)val clazz: String = e(4)(id, name, gender, age, clazz)}).foreach(println)stuArrayList.map{case Array(id: String, name: String, gender: String, age: String, clazz: String)=>(id, name, gender, age, clazz)}.foreach(println)}
}
隱式轉換
1、隱式轉換函數
import scala.io.{BufferedSource, Source}
import scala.language.implicitConversionsobject Demo24implicit {def main(args: Array[String]): Unit = {/*** 隱式轉換* 1、隱式轉換函數* 2、隱式轉換類* 3、隱式轉換變量* 一個A類型將來會自動地轉換成另一個B類型,類型可以是基本數據類型,也可以是引用數據類型** 顯式轉換*/
// var i:String = "100"
// //顯式轉換
// val res1: Int = i.toInt//定義一個函數def fun1(s: Int): Int = {return s + 1000}//調用函數println(fun1(100))println(fun1(200))
// println(fun1("300".toInt)) // 若已設置隱式轉換函數,則會報錯,因為不知道要不要交給隱式轉換函數處理//需求:調用fun1函數,就只傳字符串,不會報錯//定義隱式轉換函數//在需要返回值類型的功能的時候,自動地根據已有隱式轉換函數將參數的類型轉成返回值的類型implicit def implicitFun1(s: String): Int = {return Integer.parseInt(s)}// implicit def implicitFun2(s: String): Int = {
// return Integer.parseInt(s) + 2000
// }// def fun1(s: Int): Int = {
// return s + 1000
// }//調用函數println(fun1(100))println(fun1(200))
// println(fun1("300"))// 封裝在一個Object類中進行導入import com.shujia.jichu.Demo11._
// val stuList: List[String] = "scala/data/students.txt".getLines().toList
// val scoreList: List[String] = "scala/data/scores.txt".getLines().toListprintln("1000" + 500) // 1000500 // 使用字符串自身的+拼接功能,做字符串拼接println("1000" - 500) // 500 // 字符串中沒有-減法功能,自動使用隱式轉換中的函數,將字符串轉成數字做減法println("2000" - 500) // 1500 // 字符串中沒有-減法功能,自動使用隱式轉換中的函數,將字符串轉成數字做減法}
}object Demo11 {implicit def implicitFun3(s: String): BufferedSource = Source.fromFile(s)implicit def implicitFun1(s: String): Int = Integer.parseInt(s)
}
2、隱式轉換類
import scala.io.Source/*** 隱式轉換類*/
object Demo25implicit {def main(args: Array[String]): Unit = {// val demo1 = new Demo12("scala/data/students.txt")
// val stuList: List[String] = demo1.show1()val stuList: List[String] = "scala/data/students.txt".show1()val scoreList: List[String] = "scala/data/score.txt".show1()//TODO 使用隱式轉換類時不見其類名"張三".f()}//`implicit' modifier cannot be used for top-level objects//implicit class Demo12(path: String) {//implicit使用的地方,不能超過object作用域(將其放在object Demo25implicit中)// path: String :使用對應的上其參數類型的一個量即可調用類中的方法implicit class Demo12(path: String) {def show1(): List[String] = {Source.fromFile(path).getLines().toList}def f()={println(s"好好學習,天天向上!$path")}}}
3、隱式轉換變量
import scala.io.{Codec, Source}/*** 隱式轉換變量*/
object Demo26implicit {def main(args: Array[String]): Unit = {Source.fromFile("scala/data/students.txt")(Codec("GBK")).getLines().toList// def fun1(a1: Int)(a2: Int): Int = a1 + a2// val res1: Int=>Int = fun1(100)//定義一個隱式轉換參數def fun1(a1: Int)(implicit a2: Int): Int = a1 + a2//定義一個隱式轉換變量,若上述函數在被調用時沒有傳入第二個隱式轉換參數時,則會使用下面設定的默認值implicit var i1: Int = 1000// 只傳入一個參數值后調用fun1返回的為一個數值。若是沒有定義隱式轉換變量val res1: Int = fun1(100)println(res1)}
}