一門多正規化的程式語言Scala學習的第一天-簡介

shmil發表於2024-08-20

Scala

1、Scala簡介

1.1Scala的介紹

  • scala是一門多正規化的程式語言
  • Scala是把函數語言程式設計思想和麵向物件程式設計思想結合的一種程式語言
  • 大資料計算引擎spark是由Scala編寫的

1.2Scala的特性

1.2.1多正規化

1.2.1.1物件導向特性

Scala 是一種高度表達性的程式語言,它結合了物件導向程式設計和函數語言程式設計的最佳特性

  • 類和物件:Scala支援類和物件,可以定義屬性和方法。
  • 繼承和多型:支援類的繼承和多型,可以建立層次結構和重用程式碼。
  • 抽象類:可以定義抽象類,用於定義介面和實現部分行為
  • 封裝:支援訪問控制修飾符(public,protected,private),實現資料的封裝
1.2.1.2函數語言程式設計
  • 高階函式:函式可以作為引數傳遞給另一個函式,或者從另一個函式返回。
  • 不可變性:預設使用不可變資料結構,提高程式碼的併發安全性。
  • 模式匹配:提供強大的模式匹配功能,可以解構複雜資料結構,進行條件判斷。

1.2.2相容JAVA

  • 類庫呼叫
  • 互操作

1.2.3語法簡潔

  • 程式碼行短
  • 型別推斷
  • 抽象控制

1.2.4靜態型別化

  • 可檢驗、安全重構

1.2.5支援併發控制

  • 強計算能力、自定義其他控制結構

1.3面向函數語言程式設計和麵向物件程式設計的區別

  • 在物件導向程式設計中,我們把物件傳來傳去,那在函數語言程式設計中,我們要做的是把函式傳來傳去,而這個,說成術語,我們把他叫做高階函式。
  • 在函數語言程式設計中,函式是基本單位,,他幾乎被用作一切,包括最簡單的計算,甚至連變數都被計算所取代。在函數語言程式設計中,變數只是一個名稱,而不是一個儲存單元,這是函數語言程式設計與傳統的指令式程式設計最典型的不同之處。

1.4Scala和Java的編譯過程

  • 以Scala結尾的檔案和以Java結尾的檔案都會透過編譯之後生成 .class檔案,
  • 並且由於Scala是基於Java的,因此兩者編譯之後產生的 .class檔案是一樣的
  • 然後相應的 .class檔案會在JVM上執行,產生最終的結果

image-20240710191704602

2、Scala的相關基礎用法

注意事項

  • 1、如果需要是可執行檔案就必須將class改成object
    
  • 2、如果是class僅僅代表的是一個類,如果是object就代表的是一個單例物件
    
  • 3、在Scala中,編寫完一句程式碼結尾不需要加上";"
    
  • 4、Scala檔案中可以任意的使用Java的類和方法
    

Scala的第一個程式碼,hello world

object demo01HelloWord {

  def main(args: Array[String]): Unit = {
    println("hello world")
  }
}

2.1變數與常量

2.1.1變數

變數: 在程式執行過程中其值可能發生改變的量叫做變數。

object Demo02base {
  def main(args: Array[String]): Unit = {
    /**
     * 定義變數
     * 注意:
     *  1、變數一旦定義型別就確定了,可以不用手動指定變數的型別,Scala會根據賦予的值自動推斷出其型別
     *  2、也可以手動的指定變數的資料型別,如:var 變數名:資料型別=值
     *
     *  Scala中的資料型別和Java資料型別的對應關係
     *  Java:               scala:
     * byte                Byte
     * short               Short
     * int                 Int
     * long                Long
     * float               Float
     * double              Double
     * boolean             Boolean
     * char                Char
     */
    var a1=100
    println(a1)
    //獲取a1的資料型別
    println(a1.getClass)
    //型別不一致無法直接轉換a1的值
//    a1="hello"
//    println(a1)
    //型別一致可以直接改變變數的值
    a1=200
    println(a1)

    //定義一個整數型別的完整寫法
    var a2:Int=100
    println(a2)
    println(a2.getClass)

    // * 其實是一個函式,底層是透過StringBuilder連結字元的
    //簡化寫法將.和()省略
    println("="*50)
    println("=".*(50))
  }
}

2.1.2常量

在程式執行過程中其值不會發生變化的量叫做常量

object Demo03base {
  def main(args: Array[String]): Unit = {   
	/**
     * 定義常量:在Scala中定義一個常量,需要使用關鍵字:val
     */
    val a3:Int=50
    println(a3)
    //常量的值一旦定義就無法改變
//    a3=20
  }
}

2.2字串

scala中的字串String類和Java中的String類是共同的一個字串類

Java中字串的功能在Scala中正常使用

object Demo04base {
  def main(args: Array[String]): Unit = {
	var s3:String="hello,world,java,shujia,scala"
    val arr1: Array[String] = s3.split(",")
    //直接列印使用逗號切分的陣列,列印的是該陣列的地址值
    println(arr1)
    //Scala中的陣列和Java的陣列一致,具有索引且從0開始
    println(arr1(0))
    println(arr1(1))
    println(arr1(2))
    println(arr1(3))
    println(arr1(4))

    /**
     * scala中的字串拼接方式:
     * 1、直接使用+號,這種拼接方式比較消耗效能
     * 2、使用String Builder的append方法
     * 3、使用Scala特有的函式mkString,該方法的前提是有一組序列
     * 4、使用Scala特有的字串傳遞方法 s"${變數}" 該方法的底層是使用String Builder方式拼接的
     */
    var q1:String="hello"
    var q2:String="world"
    var q3:String="java"
    //方式1
    val res1: String = q1 + "|" + q2 + "|" + q3
    print(res1)

    //方式2
    val sb: StringBuilder = new StringBuilder()
    sb.append(q1).append("-").append(q2).append("-").append(q3)
    println(sb)

    //方法3:指定字串的分隔符
    val res2: String = arr1.mkString("|")
    println(res2)

    //方法4
    val res3: String = s"${q1.toUpperCase()}#${q2}#${q3}"
    println(res3)

  }

}

2.3scala的運算子

import java.util.Scanner
import scala.util.control.Breaks._

object Demo03 {
  def main(args: Array[String]): Unit = {
    /**
     * scala中的運算子
     */
    var x:Int=3
    var y:Int=4

    //這些運算子在Scala中其實都是函式
    println(x+y)
    println(x-y)
    println(x*y)
    println(x/y)
    println(x%y)
    //x乘以1.0之後其資料型別就上升為了double,故結果就會是double型別
    println(x*1.0/y)
    println("hello"+4)
  }
}

2.4條件語句

條件語句分為:

​ 1、選擇語句:if

​ 2、迴圈語句:while,break

  • if語句
//條件語句if
val sc: Scanner = new Scanner(System.in)
println("請輸入年齡:")
val age: Int = sc.nextInt()
if(age>18){
    println("old")
}else{
    println("young")
}
  • while迴圈

注意:

​ 1、在Scala語言中,沒有++或者--的語法,只有i+=1 或者i-=1

​ 2、在Scala語言中,不存在和Java一樣的普通for迴圈

​ 3、Scala中的for迴圈寫法不一樣

//Scala中值存在下面的for迴圈寫法
for(e<-arr1){
    println(e)
}

/**
     * while迴圈
     */
var i:Int=0
while (i<arr1.length){
    println(arr1(i))
    i+=1
}

/**
     * 需求:在控制檯中輸出10行hello world
     */
var j:Int=1
while(j<=10){
    println("hello world")
    j+=1
}

//使用for迴圈
for(e<-1 to 10){
    println(e)
}

for(e<-1 until 10){
    println(e)
}
  • 流程控制語句

注意:在scala中沒有break或者continue關鍵字,但是存在breakable

breakable{
    for(e<-1 to 10){
        if(e==5){
            // 底層實現是一個函式,丟擲一個異常,終止程式執行
            break
        }
        println(e)
    }
}
println("hello")

2.5 Scala中的IO流

注意:對於Scala來說,不存在寫檔案的方式,有讀取檔案的方式

  • 採用Java中寫檔案的方式寫入,如果檔案不存在,則會自動進行建立

  • 但是對於讀檔案,如果檔案不存在時會報錯

package com.shujia.jichu

import java.io.{BufferedReader, BufferedWriter, FileReader, FileWriter}
import scala.io.{BufferedSource, Source}
object Demo03base3 {
  def main(args: Array[String]): Unit = {
    /**
     * scala中的讀取檔案的方式
     * Source.fromFil 底層是使用了位元組輸入流讀取資料FileInputStream
     */
    val bs: BufferedSource = Source.fromFile("scala/data/words.txt")
    val iterator: Iterator[String] = bs.getLines()
    while (iterator.hasNext){
      val str: String = iterator.next()
      println(str)
    }

    //使用for迴圈的方法
    for(e<-bs.getLines()){
      println(e)
    }
      
    val bw: BufferedWriter = new BufferedWriter(new FileWriter("scala/data/words3.txt"))
    bw.write("hello shujia")
    bw.newLine()
    bw.write("java")
    //刷寫進入檔案
    bw.flush()

  }
}

2.6異常處理

  • Scala中的異常處理和Java中的類似
object Demo04Exception {
  def main(args: Array[String]): Unit = {
    try{
      println(0/0)
      //如果上面的錯誤沒有被丟擲,使用catch的方式處理,那麼下面的語句不會執行
      val arr1: Array[Int] = Array(1, 2, 3, 4)
      println(arr1(4))

    }catch{
          //相當於sql語句中的case when
        case e:ArithmeticException=>
        println("除0異常")
        e.printStackTrace()
        case e:ArrayIndexOutOfBoundsException=>
        println("陣列越界")
        e.printStackTrace()
        case _ =>
          println("出現異常")

    }finally {
      //今後finally中的處理大部分情況下都與釋放資源有關
      println("finally")
    }
  }
}


//上面是對異常進行捕獲的方式,也可以對異常進行丟擲
val sc: Scanner = new Scanner(System.in)
println("輸入除數:")
val css: Int = sc.nextInt()
if (css != 0) {
  println(10 / css)
} else {
  throw new ArithmeticException("除數為0")
}

2.7函式

/**
 * def: 定義函式或者方法的關鍵字
 * main: 是函式或者方法的名字,符合識別符號的命名規則
 * args: 函式形參的名字
 * Array[String]: 引數的資料型別是一個元素為字串的陣列
 * =: 後面跟著函式體
 * Unit: 等同於java中的void 表示無返回值的意思
 *
 *
 * def main(args: Array[String]): Unit = {
 *
 * }
 *
 * 在不同的地方定義,稱呼不一樣
 * 函式:在object中定義的叫做函式
 * 方法:在class中定義的叫做方法
 */
object Demo05Function {
  def main(args: Array[String]): Unit = {
    //函式


    def add(a1:Int,b1:Int):Int={
      return a1+b1
    }

    val res3: Int = Demo05Function.add1(100, 200)

    def fun1(s1:String):Int={
      return s1.toInt
    }

    val res1: Int = add(3, 4)
    println(res1)

    def add2(a1:Int,b1:Int):Int={
      return a1+b1
    }

    val d1: Demo01 = new Demo01()
    val res2: Int = d1.add2(11, 22)
    println(res2)

    //object中的函式呼叫方式一:可以直接透過類名進行呼叫,類似於靜態方法一樣
    val result1: Int = Demo05Function.add1(3, 4)
    println(result1)

    //呼叫方法二:可以省略類名,直接呼叫
    val result2: Int = add1(100, 200)
    println(result2)

    //方法三:如果方法呼叫的函式只有一個引數的時候,可以將.和小括號用空格代替呼叫
    val result3: Int = Demo05Function fun2 "1000"
    println(result3)

    add5


  }

  def add1(a1: Int, b1: Int): Int = {
    return a1 + b1
  }

  def fun2(s1: String): Int = {
    return s1.toInt
  }

  /**
   * 函式的定義格式
   * 1、函式有返回值,並且最後一句話作為函式的返回值的時候,return關鍵字可以不寫
   * 2、函式體只有一句話實現時,大括號可以不寫
   * 3、如果函式沒有引數時,小括號可以省略不寫
   */

    //方法一
  def add3(a1:Int,b1:Int):Int={
    a1+b1
  }

  //方法二
  def add4(a1:Int,b1:Int):Int=a1+b1

  //方法三
  def add5=println("hello")

}
class Demo01{
  def add2(a1: Int, b1: Int): Int = {
    return a1 + b1
  }
}

2.8Scala中的函式遞迴

遞迴:方法定義時,呼叫自身的現象

條件:必須存在函式出口

def main(args: Array[String]): Unit = {
    val res1: Int = jiecheng(5)
    println(res1)
    println(s"5的階乘是${Demo06Function jiecheng (5)}")
}

//求數的階乘
def jiecheng(num:Int):Int={
    if(num==1){
        1
    }else{
        num*jiecheng(num-1)
    }
}

2.9Scala中定義類

定義類的三大要素:構造方法,成員方法,成員變數

構造方法:

  • 1、在scala中構造方法的編寫和在java中不太一樣,類所擁有的大括號中都是構造程式碼塊的內容
    2、預設情況下,每一個類都應該提供一個無參的構造方法
    3、構造方法可以有許多
    
object Demo07class {
  def main(args: Array[String]): Unit = {
    val stu1: student = new student("zhangsan",19)
    println(stu1)

    val stu2: student = new student("zhangsan", 18, "nv")
    println(stu2)

    //如果呼叫的是一個函式的無參構造方法,那麼小括號可以不用寫
    val stu3: Student2 = new Student2
    stu3.fun1()

    //也可以使用多型的方式建立物件
    //多型:父類引用,指向子類物件
    val stu4: Object = new student("lisi", 19, "nan")
    println(stu4.toString)

  }
}

class student(name:String,age:Int){
  //相當於構造程式碼塊中的內容
//  println("hello world")

  /**
   * 定義成員變數
   */
  val _name:String=name
  val _age:Int=age
  //下劃線表示將來會給其賦予預設值
  var _gender:String= _

  /**
   * 構造方法可以寫多個
   */
  def this(name:String,age:Int,gender:String){
    this(name:String,age:Int)
    _gender=gender
  }

  /**
   * 也可以重寫其方法
   */
  //  override def toString:String=super.toString

  override def toString: String = {
    "姓名:" + _name + ", 年齡:" + _age + ", 性別:" + _gender
  }
}

class Student2{
  def fun1()=println("shujia666")
}

2.10樣例類

  • Scala中非常重要的功能:樣例類
  • 其最重要的特性是:
    • 減少建立類時編寫的程式碼兩,只需要定義成員變數即可,
    • 樣例類會自動擴充成員變數,構造方法,並且自動重寫了toString等方法
object Demo08caseClass {
  def main(args: Array[String]): Unit = {
    val t1: Teacher = new Teacher("zhangsan", 20, "shuijiao")
    println(t1.toString)
    println(t1.name)
    println(t1.age)
    println(t1.like)

//    t1.name="lisi"
    t1.like="eat"
    println(t1.like)
  }

}
/**
 * 樣例類中的成員變數,編譯後預設是被jvm新增了final關鍵字,使用者是改變不了的
 * 對於scala來說,預設是被val修飾的
 * 如果將來想要被改變,定義的時候需要使用var進行修飾
 */
case class Teacher(name:String,age:Int,var like:String)

2.11 伴生物件

  • 在一個Scala檔案中

    • 如果一個object物件的名字和定義的class類名一樣的話,那麼稱這個object是該class類的伴生物件
      直接在main函式中呼叫object的名字就相當於呼叫該object中的apply方法
      而一般在這個apply方法中會new建立一個上述的類的物件,便於直接呼叫
      
object Demo09apply {
  def main(args: Array[String]): Unit = {
    //普通使用的方法
    val book: Book = Book.apply("shujia", 666)
    println(book)

    //使用伴生物件的方式,呼叫object的名字就相當於呼叫該object中的apply方法
    val book1: Book = Book("shujia", 666)
    println(book1)
  }

}

object Book{
  def apply(name:String,price:Int): Book = {
    new Book(name,price)
  }
}

class Book(name:String,price:Int){
  val _name:String=name
  val _price:Int=price

  override def toString: String = "書名:" + _name + ", 價格:" + _price
}

相關文章