scala基础

Scala基础

Scala语言概况

Scala语言起源

马丁·奥德斯基(Martin Odersky)是编译器及编程的狂热爱好者。主流JVM的Javac编译器就是马丁·奥德斯基编写出来的,JDK5.0、JDK8.0的编译器就是他写的。长时间的编程之后,他希望发明一种语言,能够让写程序这样的基础工作变得高效,简单。当接触到Java语言后,对Java这门语言产生了极大的兴趣,所以决定将函数式编程语言的特点融合到Java中,由此发明了Scala。

Scala语言的特点

Scala是一门以JVM为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。Scala源代码会被编译成Java字节码,然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝互操作的。

面向对象

Scala是一种面向对象的语言。Scala中的每个值都是一个对象,包括基本数据类型(即布尔值、数字等)在内,连函数也是对象

函数式编程

Scala也是一种函数式语言,其函数也能当成值来使用。Scala中支持高阶函数,允许嵌套多层函数,并支持柯里化。Scala提供了模式匹配,可以匹配各种情况,比如变量的类型、集合的元素、有值或无值。

静态类型

Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。

并发性

Scala使用Actor作为其并发模型,Actor是类似线程的实体。Actor可以复用线程,因此可以在程序中使用数百万个Actor,而线程只能创建数千个。

为什么要学Scala

  • 优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API是否优雅直接影响用户体验。

  • 简洁:Scala语言表达能力强,一行代码抵得上Java多行,开发速度快。

  • 融合大数据生态圈:Hadoop现在是大数据事实标准,(Kafka Spark源码都是用Scala编写的,Spark Flink都支持使用Scala进行开发)Spark并不是要取代Hadoop,而是要完善Hadoop生态。


    为什么要学Scala.png

环境准备

Scala官网

1、下载Scala
2、Windows下安装Scala
3、配置IDEA开发环境
4、REPL

Scala安装和配置

Mac电脑:

解压缩scala-2.13.3.tgz,放到自己的文件目录

vim /etc/profile

export SCALA_HOME=/Users/baiwang/scala-2.13.3
PATH=$PATH:${SCALA_HOME}/bin

source /etc/profile

验证

scala

输入1 + 1返回2

Idea配置

安装Scala插件,创建Scala的项目

Scala的REPL

在命令行输入Scala可启动Scala REPL。REPL 是一个交互式解析器环境,R(read)、E(evaluate) 、P(print)、L(loop)。输入值,交互式解析器会读取输入内容并对它求值,再打印结果,并重复此过程。

基础语法

基础语法

  • 区分大小写 - Scala语言对大小写敏感;

  • 类名 - 对于所有的类名的第一个字母要大写。如果需要使用几个单词来构成一个类名,每个单词的第一个字母要大写;比如:ListDemo

  • 方法名 - 所有方法名的第一个字母用小写。如果需要使用几个单词来构成方法名,除第一个单词外每个词的第一个字母应大写;比如:getResult

  • 程序文件名 - Scala程序文件的后缀名是 .scala,程序文件的名称可以不与对象名称完全匹配。这点与Java有所区别。

    备注:建议遵循 Java 的惯例,程序文件名称与对象名称匹配;

  • main()方法 - Scala程序从main()方法开始处理,这是每一个Scala程序的入口点。main()定义在object中;

标识符。所有Scala组件都需要名称,用于对象、类、变量和方法的名称称为标识符。关键字不能用作标识符,标识符区分大小写;标识符以字母或下划线开头,后面可以有更多的字母、数字或下划线,$字符是Scala中的保留关键字,不能在标识符中使用;

基础语法.png

注释。Scala使用了与Java相同的单行和多行注释;

换行符。Scala语句可以用分号作为一行的结束,语句末尾的分号通常可以省略,但是如果一行里有多个语句那么分号是必须的。

小结:
Scala的基础语法与Java类似,但是仍然有三点不一样的地方
1、在Scala中换行符是可以省略的
2、Scala中的main方法是定义在Object中
3、Scala中程序文件名可以不与对象名称相匹配,但是建议仍然遵循Java规范,二者最好匹配。

常用类型与字面量

数据类型 描述
Byte 8位有符号补码整数。数值区间为 -128 到 127
Short 16位有符号补码整数。数值区间为 -32768 到 32767
Int 32位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807
Float 32 位, IEEE 754标准的单精度浮点数
Double 64 位 IEEE 754标准的双精度浮点数
Char 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF
String 字符序列
Boolean true或false
Unit 表示无值,相当于Java中的void,用于不返回任何结果的方法的返回类型。Unit写成()
Null 通常写成null
Nothing Nothing类型在Scala类层级的最低端,它是任何其他类型的子类型
Any Any是Scala中所有类的超类
AnyRef AnyRef是Scala中所有引用类的超类

Scala和Java一样,也是强类型语言(看对数据类型是否精细),有8种数值类型 Byte、Short、Int、Long、Float、Double、Char、Boolean 类型;和 Java 不同的是 ,这些类型都是类,有自己的属性和方法。Scala并不刻意的区分基本类型和引用类型。String 直接引用 Java.lang.String 中的类型,String在需要时能隐式转换为StringOps,因此不需要任何额外的转换,String就可以使用StringOps中的方法。

每一种数据类型都有对应的Rich类型,如RichInt、RichChar等,为基本类型提供了更多的有用操作。

-- StringOps。 
//toInt等方法都定义在StringLike中;StringOps实现了StringLike
"11".toInt

1.max(10)
1.min(10)
1.to(10)
1.until(10)

整数字面量。整数字面量有两种形式,十进制与十六进制(0X/0x开头)

-- 十六进制整数字面量
scala> val a = 0xa
a: Int = 10

scala> val a = 0X00FF
a: Int = 255

scala> val magic = 0xcafe
magic: Int = 51966

-- 十进制整数字面量
scala> val dec1 = 255
dec1: Int = 255

scala> val dec1 = 31
dec1: Int = 31

-- Long类型整数字面量
scala> val magic = 0xcafeL
magic: Long = 51966

scala> val long1 = 255L
long1: Long = 255

-- Short 或 Byte 类型,需要明确声明,否则编译器会推断为Int类型
scala> val little: Short = 32767
little: Short = 32767

scala> val littler: Byte = 127
littler: Byte = 127

浮点数字面量

-- 十进制数、可选的小数点、可选的e开头的指数
scala> val big = 3.1415926
big: Double = 3.1415926

scala> val bigger = 3.1415926e1
bigger: Double = 31.415926

-- 浮点数字面量以F/f结尾为Float类型;否则为Double类型;
scala> val litte = 0.31415926f
litte: Float = 0.31415927

scala> val litte = 0.31415926e1F
litte: Float = 3.1415925

字符字面量

scala> val a = 'A'
a: Char = A

-- 用字符的Unicode码来表示。Unicode码前128个字符就是ASCII码
scala> val b = '\u0042'
b: Char = B

-- 转义字符
scala> val mark = '\'
<console>:1: error: unclosed character literal
val mark = '\'
           ^

scala> val mark = '\\'
mark: Char = \

字符串字面量

scala> val str = "Hello Scala"
str: String = Hello Scala

// 使用三引号,保存所有的文本
var sql = """
     | select
     |     *
     | from
     |     user
     | where name = "张三"
     | """

类型转换

强制转换的格式:

val/var 变量名:值类型 = 字符串值.toXxx //Xxx表示你要转换的数据类型
//Int类型
val a:Int = 3
//double类型,隐式转换
val b :Double = a + 2.2
//Double转换成Int类型
val c = b.toInt

scala> val s1 = "123"
s1: String = 123

scala> val s2 = "12.2"
s2: String = 12.2

scala> val s3 = "false"
s3: String = false

scala> val a1 = s1.toInt
a1: Int = 123

scala> val a11= s1.toDouble
a11: Double = 123.0

scala> val a2 = s2.toDouble
a2: Double = 12.2

scala> val a22 = s2.toInt
java.lang.NumberFormatException: For input string: "12.2"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Integer.parseInt(Integer.java:580)
  at java.lang.Integer.parseInt(Integer.java:615)
  at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:272)
  at scala.collection.immutable.StringOps.toInt(StringOps.scala:29)
  ... 32 elided

scala> val a3 = s3.toBoolean
a3: Boolean = false

备注:String 类型的数据转成Char类型的数据,方式有些特殊。并不是调用toChar方法,而是toCharArray方法

惰性赋值

在开发中,会编写复杂的SQL,通常几百行甚至上千行,如果直接被加载到JVM中,会有很大的内存开销。所以当有一些变量保存的数据比较大时,而这些数据不需要马上加载到JVM内存中,就可以使用惰性加载来提高效率

语法格式:

lazy val/var 变量名 = 表达式

类层次结构

Scala中,所有的类,包括值类型和引用类型,都最终继承自一个统一的根类型Any。

Scala中定义了以下三个底层类:

  • Any是所有类型共同的根类型,Any是AnyRef和AnyVal的超类
  • AnyRef是所有引用类型的超类
  • AnyVal是所有值类型的超类


    类层次结构.png
类层次结构1.png

上图中有三个类型需要注意:

  • Null是所有引用类型的子类型

    Null类只有一个实例对象null

    null可以赋值给任意引用类型,但是不能赋值给值类型。

  • Nothing位于Scala类继承关系的底部,它是其他所有其他类型的子类型

    • Nothing对泛型结构有用 。比如,空列表Nil的类型就是List[Nothing]
    • Nothing的可以给出非正常终止的信号。比如,使用Nothing处理异常
  • Unit类型用来标识过程,过程就是没有返回值的方法,Unit类似于Java里的void。Unit只有一个实例()

-- null 不能赋值给值类型
scala> val i: Int = null
<console>:11: error: an expression of type Null is ineligible for implicit conversion
       val i: Int = null

scala> val str: String = null
str: String = null

-- 使用 Nothing 处理异常
val test = false
val thing: Int = if (test) 42 else throw new Exception("ERROR!")
    
-- Unit类型只有一个实例(),该实例没有实际意义
scala> val a = ()
a: Unit = ()

值与变量&自动推断

Scala当中的声明变量可以使用以下两种方式:

  • val,值 -- value,用val定义的变量,值是不可变的
  • var,变量 -- variable,用var定义的变量,值是可变的

在Scala中,鼓励使用val。大多数程序并不需要那么多的var变量。

声明变量时,可以不指定变量的数据类型,编译器会根据赋值内容自动推断当前变量的数据类型。

备注:简单数据类型可以省略,对于复杂的数据类型建议明确声明;

声明变量时,可以将多个变量放在一起声明。

-- val定义的变量不可更改,变量的类型编译器可以进行自动类型推断
val name = "zhangsan"
name = "李四"
-- 必要时可以指定数据类型
var name: String = null

-- 可以将多个值或变量放在一起声明
val x, y = 100;
var name, message: String = null

操作符

Scala的算术操作符、位操作符与 Java中的效果一样的。

需要特别注意一点:Scala中的操作符都是方法

a + b 等价 a.+(b)
1 to 10 等价 1.to(10) 

书写时推荐使用:a + b 、1 to 10这种代码风格。

Scala 没有提供 ++、-- 操作符,但是可以使用+=、-=

块表达式和赋值语句

{} 块包含一系列表达式,其结果也是一个表达式,块中最后一个表达式的值就是块的值。

赋值语句返回Unit类型,代表没有值;

val x1 = 1
val y1 = 1
val x2 = 0
val y2 = 0
val distance = {
    val dx = x1 - x2
    val dy = y1 - y2
    math.sqrt(dx*dx + dy*dy)
}

-- 赋值语句的值是Unit类型,不要把它们串接在一起。x的值是什么?
var y = 0
val x = y = 1

输入和输出

需要依赖的包:scala.io.StdIn

通过readLine 从控制台读取一行输入。

如果要读取数字、Boolean或者字符,可以用readInt、readDouble、readByte、readShort、readLong、readFloat、readBoolean或者readChar。

print、println、printf 可以将结果输出到屏幕;

-- printf 带有C语言风格的格式化字符串的 printf 函数
printf("Hello, %s! You are %d years old.", "Scala", 18)
object ReadLinePrintDemo {

  def main(args: Array[String]): Unit = {

    print("请输入你的姓名:")
    val name = scala.io.StdIn.readLine()
    print("请输入你的年龄:")
    val age = scala.io.StdIn.readInt()

    println("你的姓名:" + name + " ,你的年龄: " + age)
    printf("你的姓名:%s ,你的年龄: %d", name, age)
    println()
    println(s"你的姓名:$name ,你的年龄: $age")
  }

}

字符串插值器

Scala 提供了三种字符串插值器:

  • s 插值器,对内嵌的每个表达式求值,对求值结果调用toString,替换掉字面量中的那些表达式
  • f 插值器,它除s插值器的功能外,还能进行格式化输出,在变量后用%指定输出格式,使用 java.util.Formatter中给出的语法
  • raw 插值器,按照字符串原样进行输出
/**
 * @description: scala中的插值器
 * @date: 2020-09-22 18:52
 **/
object InterpolatorDemo {

  def main(args: Array[String]): Unit = {

    // s 插值器可以通过$变量和表达式的值
    val subject = "world"
    val message = s"hello $subject"
    println(message)
    val array = (1 to 10).toArray
    println(s"length :${array.length}")
    println(s"${9 * 10}")

    // f 插值器,用%指定输出格式
    val year = 2020
    val month = 9
    val day = 22
    println(s"$year-$month-$day")
    //以yyyy-MM-dd的方式显示,不足两位用0填充
    println(f"$year-$month%02d-$day%02d")

    // raw插值器,将字符串原样输出
    println("a\n\tc")
    println(raw"a\n\tc")
    println("""a\n\tc""") //这种模式输出与上面raw插值器输出相同
  }
}

对象相等性

Java 中可以 == 来比较基本类型和引用类型:

  • 对基本类型而言,比较的是值的相等性
  • 对引用类型而言,比较的是引用相等性,即两个变量是否指向JVM堆上的同个对象

Scala中,要比较两个基础类型的对象是否相等,可以使用 == 或 !=;

1 == 1
1 != 2
2 == 2

== 或 != 可以比较同一类型的两个对象;

List(1,2,3) == List(1,2,3)
List(1,2,3) != Array(4,5,6)

== 或 != 还可以比较不同类型的两个对象:

2 == 2.0
List(1,2,3) == "Scala"
/**
 * @description:
 * @date: 2020-09-22 19:05
 **/
object ObjectCompareDemo {

  def main(args: Array[String]): Unit = {

    println(1 == 1) // true
    println(1 != 2) // true
    println(1 == 2) // false

    val flag = List(1, 2, 3) == List(4, 5, 6)
    println(flag) // false

    println(List(1, 2, 3) != Array(1, 2, 3)) // true

    println(2 == 2.0) // true
    println(List(1, 2, 3) == "Scala")  // false
  }
}

运算符

没有 ++ 和 -- ,有 +,- ,*,/。

乘号:*

//scala中的乘号不仅仅有乘法的意思,当字符串 * 整型。表示字符串复制整型份数
scala> println("_" * 2)
__

取余%

格式:

a % b = a - a/b * b

位运算符

8421码
8421.png
原反补码.png

位运算符.png

位运算符

scala> val a = 5 //0b0000 0101
a: Int = 5

scala> val b = 3 //0b0000 0011
b: Int = 3

scala> print
print   printf   println

scala> println(a & b) //0b0000 0001
1

scala> println(a | b) //0b0000 0111
7

scala> println(a^b) // 0b0000 0110
6

scala> println(~b) //0b1111 1100 -> 0b1111 1011 ->0b1000 0100
-4

scala> println(~b) //0b1111 1100 -> 0b1111 1011 ->0b1000 0100
-4

scala> println(~(-3)) //0b1000 0011 -> 0b1111 1100 ->0b1111 1101 -> 0b0000 0010
2

scala> println(a >> 2) //0b0000 0101 ->0b0000 0001
1

scala> println(a << 2) //0b0000 0101 ->0b0001 0100
20

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容