为什么学习Scala?
因为需要学习Spark,而Spark框架开发使用最好的语言就是Scala,虽然Java也可以进行Spark的开发,但是不如Scala效率高,并且市面上大家都是使用Scala开发,遇到问题方便交流学习。并且Scala是在JVM上运行的,可以与Java代码互相操作。
因为之前一直使用Java语言作为主要开发语言,学习起Scala感觉不太适应,因为Scala极简的语法和很多固定操作需要掌握,固定操作比_,方法的简洁写法等等,一个功能Java语言需要100行实现,Scala可能只需要十几行就可以完成,极简的方式导致可读性比较低。
个人觉得应对这些困难的方式就是刻意练习,把几种常用的比较难理解的固定写法多练多记。
唠唠叨叨,接下来开始学习!!!
一、Scala简介
Scala是一种针对JVM将面向对象和函数式编程技术组合在一起的编程语言。Scala既是面向对象,又是面向函数语言。那么什么是面向对象,什么是面向函数呢?有什么特点,有什么区别呢?
面向对象:什么是对象?就是把一个小功能拆解成一块,比如一个计算器功能可以拆解为普通计算器对象,多功能计算器对象等;或者说对象就是某一类食物的具体展现。
想要创建对象就需要有一个类,比如人类这个类,那么对象就是一个具体的人。
面向对象的思想就是把人类这个大的类的一些共同的行为抽象出来,然后创建不同的具体对象,实现不同的行为。 类是对象的抽象,对象是类的具体实现。
面向函数:个人理解函数式编程相对于面向对象编程,更注重的是函数的运用,函数是程序中的单位。
极简原则:不用写的东西都可以省略
Scala的六大特性:
- Java可以和Scala混编
- 类型推测 :定义变量的时候如果不指定具体的类型,赋值之后,Scala会根据变量和所赋的值自动推断出变量的类型。
- 并发式和分布式 Scala1.6之前使用Actor通信模型,实现通信;1.6之后使用netty实现通信。不必考虑锁的问题。
- Trait: 特质、特征:相当于Java中的抽象类和接口的组合体,可以定义变量和常量,可以写含有方法体的方法,也可以写没有方法体的方法(抽象方法)
- 模式匹配:类比于Java中的switch case,但是要比Java中的switch case功能多。可以对不同类型的数据进行匹配,并且可以进行值和类型的匹配。
- 高阶函数:这一部分个人认为这一部分是Scala区别于Java最重要的部分,说的简单点就是方法可以赋值给一个变量,方法可以作为另一个方法的参数等等,也就是说方法可以像Java中的一个对象去操作,方法也可以是被当作一个对象。
二、Scala基础
1、数据类型
Byte、Short、Int、Long、Float、Double Char String Boolean 这些数据类型和java中的数据类型一样
需要特别指出的特有类型:
- Unit 表示无值,和其他语言中的void等同
- Null 空值或者空引用
- Nothing 所有其他类型的子类型,表示没有值;用于类型推断不出来的时候作为范型
val list:List[Nothing]=List()
// 这个时候创建list的时候没有指定具体的类型,类型推断不出来,就认定为Nothing类型
- Any 所有类型的超类,任何实例都属于Any类型,但是Any类型是Object类的子类,算得上是一人之下,万人之上
- AnyRef 所有引用类型的超类,比如NUll类型
- AnyVal 所有值类型的超类 比如Int,Double类型
None: Option的两个子类之一,另一个是some,用于安全的函数返回值。避免出现空指针异常,会返回None
Nil :长度为0的List
2、变量与常量的声明
(1)
var 用于定义变量
var a=2
a =3
//变量定义好之后也可以重新赋值
val 用于定义常量,常量定义好之后不能再赋值。相当于Java中的final
val a=2
a =3 //这里会报错
//变量定义好之后也可以重新赋值
(2)定义变量或者常量的时候,可以写上类型,一般都不写,Scala可以进行类型推断,比如
val a=2
val a:Int=2
//上边两种方式都可以
(3)表达式赋值
//当表达式中返回的值类型都一样的时候,类型推断出是具体的类型
val y:Int=if(a>0) 1 else -1
//当表达式中返回的值类型不一样的时候,类型推断的就是Any类型,任意类型
val x:Any=if(a>0) 1 else "haha"
val value2: Any = if(a>0) new Person("haha")
//当表达式中含有未知数据的时候,类型推断的是AnyVal类型,值类型。这是根据已知的类型推断出来的
var value1: AnyVal =if (a>0) 1
//value1现在被推断成Anyval类型的话,那么再给value1变量赋值引用类型会怎样呢?
value1=new Person("xiaoxin") //这里会报错,因为person是引用类型,不能复制给AnyVal类型的变量。
//这个时候指定value1是Any类型,就没有问题了
var value1: Any =if (a>0) 1
//value1现在被推断成Anyval类型的话,那么再给value1变量赋值引用类型会怎样呢?
value1=new Person("xiaoxin") //这里会报错,因为person是引用类型,不能复制给AnyVal类型的变量。
建议使用val,因为便于内存回收
三、Scala的类和对象
1、类 class
Scala中的类和Java中的类概念相同,这里主要注意几点区别:
类的定义:
// class Person(val name:String){ 参数前边使用val,表示为私有的,外界不可以访问
// class Person(var name:String){ 参数前边使用var,表示为可见的,等同于public
//类属性自带gatter、setter方法,也就是下边name和age都有自己的getter、setter方法
class Person(name:String){ //这里就是Person的默认构造函数
var gender=2
println("hhah")// 直接写代码块,相当于静态代码块
def this(xname:String,age:Int) { //构造函数重载一定要复写默认构造函数,使用this关键字
this(xname)
gender=age
}
}
val p=new Person("haha")
2、对象 object
被Object修饰的类,这里称为对象,类似于Java中的单例,工具类;object中定义的全部都是静态的。 使用的时候也可以传参,传参默认调用的是内部的apply方法。apply可以被重载。
class Person(name:String){
var gender=2
def this(xname:String,age:Int) {
this(xname)
gender=age
ScalaGrammar(name)
ScalaGrammar("ah",9) //默认调用apply方法
}
}
object ScalaGrammar { //相当于是Java中的单例
def main(args: Array[String]): Unit = {
}
def apply(name:String)={
}
def apply(name:String,age:Int)={
}
}
3、伴生对象以及伴生类
当一个文件中的对象名和类名相同的时候,互为伴生,可以相互访问对方内部的私有变量。
object ScalaGrammar {
val yyyname="ooo"
def main(args: Array[String]): Unit = {
val grammar = new ScalaGrammar()
grammar.xxxname
}
}
class ScalaGrammar(){
val xxxname="xixix"
def yy(): String ={
ScalaGrammar.yyyname
}
}
四、条件、循环
0、to 和until的用法
to和until都是获取一段整数范围,until与to的区别在于不取最后一个数,左闭右开。
1 to 10
等同于
1.to(10)
获取的是1-10的整数
1.to(10,3) 步长概念,跨三个数取一个数 1,4,7,10
1 until (10) 1-9
他们的底层都是range
range(1,10)
range(1,10,3) 步长
range和until一样,都是左闭右开
1、if else
条件查询写法和Java很像。
if (age>10){
print("111")
}else if(age>20){
print("222")
}else{
print("333")
}
2、循环
(1)、for
for语句中的特定写法,<- 让我想起了大学学c语言,指针好像就是使用这个,当时对这个很抵触,现在看到依然很恐惧。不过它只是个固定写法,记住就行了。
这里最重要的就是记住<-的固定写法,类似于in的用法。
for(i <- 0.to(10)){
println(i)
}
val arr=Array[Int](1,2,3,4,2,3,4)
for(i<- arr){
println(i)
}
(2)、多层for循环
多层循环可以使用卸载一个for中,使用;隔开,这样构成多层for循环
val arr=Array[Int](1,2,3,4,2,3,4)
var count =1
for(i<- arr){
for(j<-0.to(20)){
println(i+j)
count+=1
}
}
//等同于
for(i<-arr;j<-0.to(20)){
println(i+j)
count+=1
}
scala中年不能使用i++,i--,只能使用i+=1;
for循环中有条件语句,也可以写到for语句中
val arr=Array[Int](1,2,3,4,2,3,4)
for(i<- arr){
if(i%2==0){
if(i>4) {
print(i)
}
}
}
//等同于
for(i<-arr;if(i%2==0);if(i>4)){
println(i)
}
yield关键字,将for循环的结果转化成一个集合
val ints: Array[Int] = for (i <- arr; if (i % 2 == 0); if (i > 4)) yield i
(3)、while do-while循环
while循环
val arr=Array[Int](1,2,3,4,2,3,4,6,8,9,10)
val ints: Array[Int] = for (i <- arr; if (i % 2 == 0); if (i > 4)) yield i
val iterator = ints.iterator
while(iterator.hasNext){
println(iterator.next())
}
do-while循环:先执行语句,再循环
val arr=Array[Int](1,2,3,4,2,3,4)
val ints: Array[Int] = for (i <- arr; if (i % 2 == 0); if (i > 4)) yield i
val iterator = ints.iterator
do{
println(iterator.hasNext) //当第一次进来取不到值的时候会报错
}while(iterator.hasNext)