柚子快報邀請碼778899分享:開發(fā)語言 后端 Scala
柚子快報邀請碼778899分享:開發(fā)語言 后端 Scala
數(shù)據(jù)類型:
Unit 表示無值,和其它語言中void相同
Null 空值或空引用
Nothing 所有類型的子類型,表示沒有值
Any 所有其它類型的超類,任何實例都是Any類型
AnyRef 所有引用類型的超類
AnyVal? 所有值類型的超類
var和val的區(qū)別:var是可變量,val是不可變量(相當于java中的final)。
val支持推導類型,即根據(jù)變量的初始值推導出變量的類型,但var必須顯式聲明
val線程安全,因為它不可變,不會引起結果的差異和競態(tài)條件。
val更適合函數(shù)式編程
競態(tài)條件(Race Condition)是指在多線程編程中,多個線程對共享資源的訪問和操作沒有正確同步導致的不確定結果。競態(tài)條件可能會導致程序出現(xiàn)意外的行為,產(chǎn)生不一致的結果。
競態(tài)條件發(fā)生的原因是多個線程并發(fā)執(zhí)行時,它們對共享資源的訪問沒有進行適當?shù)耐讲僮?。這意味著多個線程可以以任意的順序讀取和寫入共享資源,導致操作結果的不可預測性。
以下是一些常見的競態(tài)條件情況:
讀-修改-寫(Read-Modify-Write)操作:多個線程同時讀取同一個變量的值,并根據(jù)這個值進行修改后再寫回。如果多個線程同時執(zhí)行讀取和寫入操作,可能會導致最終結果不正確。 檢查-執(zhí)行(Check-Then-Act)操作:多個線程同時檢查某個條件,并根據(jù)條件執(zhí)行相應的操作。如果多個線程同時執(zhí)行檢查操作,可能導致條件的結果在執(zhí)行操作之前被修改,從而產(chǎn)生錯誤的行為。 非原子操作:多個線程同時執(zhí)行多個操作,這些操作需要以原子方式執(zhí)行才能保證正確性。如果沒有適當?shù)耐酱胧赡軐е虏僮髦g的交叉執(zhí)行,產(chǎn)生不一致的結果。
為了避免競態(tài)條件,需要使用適當?shù)耐綑C制來保護共享資源的訪問,例如使用鎖(Lock)、互斥量(Mutex)、信號量(Semaphore)等。這些同步機制可以確保多個線程按照正確的順序訪問共享資源,避免競態(tài)條件的發(fā)生。
在Java和Scala中,數(shù)值類型之間的轉(zhuǎn)換關系如下:
從較小的類型向較大的類型轉(zhuǎn)換是自動進行的,稱為隱式類型轉(zhuǎn)換。這是因為較小的類型可以容納較大類型的值,不會導致數(shù)據(jù)丟失或溢出。
Byte 可以自動轉(zhuǎn)換為 Short、Int、Long、Float、Double。Short 可以自動轉(zhuǎn)換為 Int、Long、Float、Double。Char 可以自動轉(zhuǎn)換為 Int、Long、Float、Double。Int 可以自動轉(zhuǎn)換為 Long、Float、Double。Long 可以自動轉(zhuǎn)換為 Float、Double。Float 可以自動轉(zhuǎn)換為 Double。
從較大的類型向較小的類型轉(zhuǎn)換需要顯式進行,稱為顯式類型轉(zhuǎn)換或強制類型轉(zhuǎn)換。這是因為較大的類型可能無法完全容納較小類型的值,可能會導致數(shù)據(jù)丟失或溢出。
Double 需要顯式轉(zhuǎn)換為 Float、Long、Int、Short、Byte。Float 需要顯式轉(zhuǎn)換為 Long、Int、Short、Byte。Long 需要顯式轉(zhuǎn)換為 Int、Short、Byte。Int 需要顯式轉(zhuǎn)換為 Short、Byte。Short 需要顯式轉(zhuǎn)換為 Byte。
val intValue: Int = 1000
val byteValue: Byte = intValue.toByte
val doubleValue: Double = 3.14
val intValue: Int = doubleValue.toInt
隱式轉(zhuǎn)換案例
通過定義一個隱式轉(zhuǎn)換函數(shù) intToString,它接受一個 Int 類型的參數(shù),并將其轉(zhuǎn)換為 String 類型。然后,在主函數(shù)中將 intValue 賦值給 stringValue 變量時,由于沒有直接的類型匹配,編譯器會自動應用隱式類型轉(zhuǎn)換函數(shù)將 intValue 隱式轉(zhuǎn)換為 String 類型。
// 定義一個隱式轉(zhuǎn)換函數(shù)
implicit def intToString(value: Int): String = value.toString
def main(args: Array[String]): Unit = {
val intValue: Int = 42
// 隱式類型轉(zhuǎn)換:將 intValue 轉(zhuǎn)換為 String 類型
val stringValue: String = intValue
println(stringValue)
}
if-else舉例
def main(args: Array[String]): Unit = {
val x = 10
if (x > 5) {
println("x is greater than 5")
} else {
println("x is less than or equal to 5")
}
}
for循環(huán)
for(i <- 1 to 9;j <- 1 until 10){
}
scala中沒有break和continue的實現(xiàn),但可以通過breakable關鍵字和遞歸函數(shù)替代實現(xiàn)。
使用breakable{}代碼塊包裹需要使用break功能的代碼塊
import scala.util.control.Breaks._
var i = 0
breakable {
while (i < 10) {
if (i == 5) break // 使用 breakable 塊中的 break 方法實現(xiàn)中斷循環(huán)
println(i)
i += 1
}
}
遞歸
def printNumbers(n: Int): Unit = {
if (n < 1) return // 遞歸終止條件
if (n == 5) return // 使用 return 語句實現(xiàn)跳過當前迭代
println(n)
printNumbers(n - 1) // 遞歸調(diào)用
}
printNumbers(10)
方法的定義:Method
def fun(x int ,y int) :unit = {
}
def fun1 (a : Int , b : Int)= a+b
方法可以寫返回值的類型也可以不寫,會自動推斷,有時候不能省略,必須寫,比如在遞歸方法中或者方法的返回值是函數(shù)類型的時候。scala中方法有返回值時,可以寫return,也可以不寫return,會把方法中最后一行當做結果返回。當寫return時,必須要寫方法的返回值。如果返回值可以一行搞定,可以將{}省略不寫傳遞給方法的參數(shù)可以在方法中使用,并且scala規(guī)定方法的傳過來的參數(shù)為val的,不是var的。如果去掉方法體前面的等號,那么這個方法返回類型必定是Unit的。這種說法無論方法體里面什么邏輯都成立,scala可以把任意類型轉(zhuǎn)換為Unit.假設,里面的邏輯最后返回了一個string,那么這個返回值會被轉(zhuǎn)換成Unit,并且值會被丟棄。
函數(shù)Function
定義一個函數(shù)
val? f1=(x:Int,y:Int)=>x+y
調(diào)用: f1(1,2)
匿名函數(shù)
(x:Int,y:Int)=>x+y
函數(shù)和方法的區(qū)別:函數(shù)式獨立的、可單獨調(diào)用的代碼塊,方法是類對象中的一個成員,通過類的實例進行調(diào)用
函數(shù)式編程:
高階函數(shù):返回值是函數(shù),或參數(shù)是函數(shù),或同時都是的函數(shù)
返回值是函數(shù)的函數(shù):
def f(a:int,b:int):(int,int)=>int ={
def f2(x:int,y:int):int={
x+y+a+b
}
f2
}
println(f(1,2)(3,4))
//函數(shù)的返回是函數(shù)
//1,2,3,4相加
def hightFun2(a : Int,b:Int) : (Int,Int)=>Int = {
def f2 (v1: Int,v2:Int) :Int = {
v1+v2+a+b
}
f2
}
println(hightFun2(1,2)(3,4))
這段代碼定義了一個高階函數(shù) hightFun2,它接受兩個整型參數(shù) a 和 b,并返回一個函數(shù) (Int, Int) => Int。
函數(shù) hightFun2 內(nèi)部定義了一個局部函數(shù) f2,它接受兩個整型參數(shù) v1 和 v2,并返回它們的和再加上外部參數(shù) a 和 b 的值。這個局部函數(shù) f2 捕獲了外部函數(shù) hightFun2 的參數(shù) a 和 b,因此在函數(shù)體內(nèi)部可以直接訪問這兩個參數(shù)。
最后,函數(shù) hightFun2 返回了局部函數(shù) f2。在打印語句中,我們通過 hightFun2(1, 2) 調(diào)用了 hightFun2 函數(shù),并將返回的函數(shù) (Int, Int) => Int 作為參數(shù)傳遞給了另一個函數(shù)調(diào)用 println。然后,我們通過 (3, 4) 作為參數(shù)調(diào)用了這個返回的函數(shù),得到結果 1 + 2 + 3 + 4 = 10,并將結果打印出來。
因此,整體來說,這段代碼的含義是定義了一個接受兩個參數(shù)的高階函數(shù) hightFun2,它返回一個函數(shù),這個返回的函數(shù)接受兩個參數(shù),并返回這兩個參數(shù)的和再加上外部傳入的參數(shù)的值。然后,通過調(diào)用 hightFun2(1, 2)(3, 4),得到了最終的結果并打印出來。
def hightFun3(f : (Int ,Int) => Int) : (Int,Int) => Int = {
f
}
println(hightFun3(f)(100,200))
println(hightFun3((a,b) =>{a+b})(200,200))
//以上這句話還可以寫成這樣
//如果函數(shù)的參數(shù)在方法體中只使用了一次 那么可以寫成_表示
println(hightFun3(_+_)(200,200))
這段代碼定義了一個高階函數(shù) hightFun3,它接受一個函數(shù) f,該函數(shù)的類型為 (Int, Int) => Int,并返回一個函數(shù) (Int, Int) => Int。
在第一個打印語句中,我們調(diào)用了 hightFun3(f),將函數(shù) f 作為參數(shù)傳遞給 hightFun3,然后將返回的函數(shù)再次調(diào)用,并傳入?yún)?shù) (100, 200)。由于函數(shù) hightFun3 的實現(xiàn)中直接返回了參數(shù)函數(shù) f,因此第一個打印語句的結果就是調(diào)用函數(shù) f,即 f(100, 200)。
在第二個打印語句中,我們調(diào)用了 hightFun3,并傳入了一個匿名函數(shù) (a, b) => { a + b }。這個匿名函數(shù)接受兩個參數(shù),并返回它們的和。因此,第二個打印語句的結果就是調(diào)用這個匿名函數(shù),即 (a, b) => { a + b }(200, 200),最終結果為 400。
注意點:{}中最后一行為默認返回值
匿名函數(shù) 中的參數(shù)如果只使用一次,可以 簡寫,即? (a,b)=>{a+b} 簡化為 (_+_)
柯里化函數(shù): 高階函數(shù)調(diào)用的簡化
將原來需要接受多個參數(shù)的函數(shù)轉(zhuǎn)換成只要一個參數(shù)的函數(shù)過程,并且返回 一個函數(shù)(參數(shù)為 剩余的參數(shù))。
scala柯里化風格的使用可以簡化主函數(shù)的復雜度,提高主函數(shù)的自閉性,提高功能上的可擴張性、靈活性??梢跃帉懗龈映橄?功能化和高效的函數(shù)式代碼。
//柯理化
object KLH {
def main(args: Array[String]): Unit = {
def klh(x:Int)(y:Int) =x*y
val res=klh(3)(_)
println(res(4))
// KLH(3)(_)(4)
}
}
/**
* 柯里化函數(shù)
*/
def fun7(a :Int,b:Int)(c:Int,d:Int) = {
a+b+c+d
}
println(fun7(1,2)(3,4))
// val res = fun7(1,2)_
// val res1 = res(3,4)
接下來,使用 klh(3)(_)(4) 的方式調(diào)用柯里化函數(shù)。其中,第一個參數(shù)列表 klh(3) 接受參數(shù) 3,并返回一個函數(shù),這個函數(shù)需要一個參數(shù) y。而 _ 表示占位符,代表后續(xù)需要傳入的參數(shù)。
然后,將返回的函數(shù)賦值給變量 res。最后,通過 res(4) 調(diào)用這個函數(shù),將參數(shù) 4 傳遞給 res,并輸出結果。
因此,程序的輸出結果為 12,即 3 * 4。
面向?qū)ο?/p>
scala和java在繼承方面的區(qū)別:
1.java只能單繼承,scala通過trait實現(xiàn)多重繼承(一個類可以繼承多個父類),即混入mixin。
2.trait,類似于java中的接口,比接口強大。定義一組方法的規(guī)范,但java在接口里不會寫實現(xiàn),而scala包含具體的實現(xiàn)。
3.構造方法,java中的是與類同名的特殊方法,scala中是對象中一個代碼塊。
4.方法重寫:java使用@override注解,scala直接使用override關鍵字
單例對象
某個對象的實例在整個應用程序的生命周期內(nèi)是唯一的,類似于java單例模式。使用Singleton Object創(chuàng)建只有一個實例的類。
object SingletonExample {
def sayHello(): Unit = {
println("Hello, I am a singleton object!")
}
}
SingletonExample.sayHello()
伴生對象
scala允許定義和class結構同名的object結構object稱之為伴生對象class稱之為伴生類當只有object對象時,我們也稱這個對象為單例對象、孤立對象
集合
數(shù)組 使用 Array 類型表示,可變長度的有序集合,使用索引訪問元素? val array = Array(1, 2, 3, 4)
list列表 使用 List 類型表示,不可變的有序集合,可以通過 :: 運算符構建新的列表。 val list = List(1, 2, 3, 4)
set 去重,不可變
/**
* 可變長Set
*/
import scala.collection.mutable.Set
val set = Set[Int](1,2,3,4,5)
set.add(100)
set.+=(200)
set.+=(1,210,300)
set.foreach(println)
map k-v類型的集合 val map = Map("a" -> 1, "b" -> 2, "c" -> 3)
元組 可以包含不同類型的元素,用()包裹
隊列(Queue):使用 Queue 類型表示,可變的先進先出集合。
import scala.collection.mutable.Queue
val queue = Queue(1, 2, 3, 4)
可變集合在操作時可以修改其內(nèi)容,而不可變集合的操作會返回一個新的集合,原集合保持不變。
scala集合常用的計算函數(shù)
sum:計算集合中元素的總和。
val numbers = List(1, 2, 3, 4, 5) val total = numbers.sum println(total) // 輸出:15
max:返回集合中的最大值。
val numbers = List(1, 2, 3, 4, 5) val maxNum = numbers.max println(maxNum) // 輸出:5
min:返回集合中的最小值。
val numbers = List(1, 2, 3, 4, 5) val minNum = numbers.min println(minNum) // 輸出:1
average:計算集合中元素的平均值。
val numbers = List(1, 2, 3, 4, 5) val avg = numbers.sum.toDouble / numbers.length println(avg) // 輸出:3.0
count:統(tǒng)計滿足特定條件的元素個數(shù)。
val numbers = List(1, 2, 3, 4, 5) val evenCount = numbers.count(_ % 2 == 0) println(evenCount) // 輸出:2
filter:過濾集合中滿足特定條件的元素。
val numbers = List(1, 2, 3, 4, 5) val evenNumbers = numbers.filter(_ % 2 == 0) println(evenNumbers) // 輸出:List(2, 4)
map:對集合中的每個元素應用某個函數(shù)并返回新的集合。
val numbers = List(1, 2, 3, 4, 5) val doubledNumbers = numbers.map(_ * 2) println(doubledNumbers) // 輸出:List(2, 4, 6, 8, 10)
模式匹配
case關鍵字,每個備選項都包含一個模式和一個或多個表達式? => 隔開了模式和表達式
1.可以匹配值和類型
2.從上到下匹配,匹配上了就不會再往下匹配
3. 都匹配不上時,會匹配case _ 相當于匹配默認值
4.match 的{}? 可以去掉
def matchTest(x:Any) ={
x match {
case x:Int=> println("type is Int")
case 1 => println("result is 1")
case 2 => println("result is 2")
case 3=> println("result is 3")
case 4 => println("result is 4")
case x:String => println("type is String")
// case x :Double => println("type is Double")
case _ => println("no match")
}
}
}
match {
case a =>
case b =>
case c =>
}
偏函數(shù):方法中沒有match只有case
異常
將會發(fā)生異常的代碼封裝在 try 塊中。在 try 塊之后使用了一個 catch 處理程序來捕獲異常。如果發(fā)生任何異常,catch處理程序?qū)⑻幚硭?,程序?qū)⒉粫惓=K止。Scala 的異常的工作機制和 Java 一樣,但是 Scala 沒有“checked(編譯期)”異常,即 Scala沒有編譯異常這個概念,異常都是在運行的時候捕獲處理。異常捕捉的機制與其他語言中一樣,如果有異常發(fā)生,catch 子句是按次序捕捉的。因此,在 catch 子句中,越具體的異常越要靠前,越普遍的異常越靠后,如果把越普遍的異常寫在前,把具體的異常寫在后,在 Scala 中也不會報錯,但這樣是非常不好的編程風格。 object Test_Exception {
def main(args: Array[String]): Unit = {
try{
val n =10 /0;
}catch {
case e: ArithmeticException =>{
println("發(fā)生算數(shù)異常")
}
case e: Exception => {
println("發(fā)生一般異常")
}
}finally {
println("處理結束")
}
}
}
object a {
def main():Unit = {
try{
}
catch{
//模式匹配
case e : 異常處理類 => {}
}
finally{
}
}
}
隱式轉(zhuǎn)換
類型匹配時,如果找不到合適的類型,會讓編譯器在作用范圍內(nèi)自動推斷類型
隱式方法,即隱式轉(zhuǎn)換函數(shù)
使用關鍵字 implicit修飾,當A對象調(diào)用一個方法時,發(fā)現(xiàn)A類里面沒有這樣的方法,但B類中存在這個方法,那么編譯器就會在作用域里面找有沒有可以將A類對象轉(zhuǎn)換B類對象的隱式轉(zhuǎn)換函數(shù),如果有,就使用,A類就可以調(diào)用該方法。
class Animal(name:String){
def canFly(): Unit ={
println(s"$name can fly...")
}
}
class Rabbit(xname:String){
val name = xname
}
object Lesson_ImplicitFunction {
implicit def rabbitToAnimal(rabbit:Rabbit):Animal = {
new Animal(rabbit.name)
}
def main(args: Array[String]): Unit = {
val rabbit = new Rabbit("RABBIT")
rabbit.canFly()
隱式參數(shù):方法的參數(shù)用implicit關鍵字修飾,必須用KLH的方式書寫,寫在后面的()中
隱式轉(zhuǎn)換的作用是當調(diào)用方法時,不用傳參,編譯器會自動在作用域范圍內(nèi)搜尋并將隱式參數(shù)傳入
隱式類:用implicit修飾的類。當A變量沒有某個方法,可以在定義一個隱式類,在里面定義方法,然后隱式類的方法傳給A去實現(xiàn)
隱式類注意:
1).隱式類必須定義在類,包對象,伴生對象中。
2).隱式類的構造必須只有一個參數(shù),同一個類,包對象,伴生對象中不能出現(xiàn)同類型構造的隱式類。
隱式轉(zhuǎn)換機制即隱式轉(zhuǎn)換函數(shù)或類和隱式參數(shù)
泛型:通用的類、方法、函數(shù),可以接受各種類型的參數(shù),提高代碼靈活性。
class Box[T](value: T) {
def getValue: T = value
}
val boxInt = new Box[Int](42)
val boxString = new Box[String]("Hello")
val intValue: Int = boxInt.getValue
val stringValue: String = boxString.getValue
柚子快報邀請碼778899分享:開發(fā)語言 后端 Scala
文章鏈接
本文內(nèi)容根據(jù)網(wǎng)絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權,聯(lián)系刪除。