Spark学习2 ——scala基础

csdn排版垃圾,参见倔金

最佳参考

  • Scala语言的名称来自于“可伸展的语言”,从写个小脚本到建立个大系统的编程任务均可胜任。
  • Scala运行于Java平台(JVM,Java 虚拟机)上,并兼容现有的Java程序,Scala代码可以调用Java方法,访问Java字段,继承Java类和实现Java接口。

Scala具有以下突出的优点:

  1. Scala具备强大的并发性,支持函数式编程,可以更好地支持分布式系统;
  2. Scala语法简洁,能提供优雅的API;
  3. Scala兼容Java,运行速度快,且能融合到Hadoop生态圈中。

一、Scala基础

1. 声明值和变量

Scala有两种类型的变量,一种是val,另一种是var

  • val 是不可变的,在声明时就必须被初始化,而且初始化以后就不能再赋值
  • var 是可变的,声明的时候需要进行初始化,初始化以后还可以再次对其赋值。
val变量
val myStr = "Hello World!"			// myStr: String = Hello World!  Scala具有“类型推断”能力 
val myStr2 : String = "Hello World!"   //  显式声明变量的类型
// Scala注释很像Java和C ++注释。多行注释以/*开头,以*/结束。 // 单行注释
var变量
  • 如果一些变量,需要在初始化以后还要不断修改它的值(比如商品价格),则需要声明为var变量。
var myPrice : Double = 9.9
myPrice = 10.6  // 再次对myPrice进行赋值
val myStr4 =
       | "Hello World!"  // 在Scala解释器中输入多行代码

2. 基本数据类型和操作

基本数据类型
  • Scala的数据类型包括:Byte、Char、Short、Int、Long、Float、Double和Boolean。
  • 和Java不同的是,在Scala中,这些类型都是“类”,并且都是包scala的成员,比如,Int的全名是scala.Int。对于字符串,Scala用java.lang.String类来表示字符串。
操作符
  • 在Scala中,可以使用加(+)、减(-) 、乘(*) 、除(/) 、余数(%)等操作符,而且,这些操作符就是方法

  • 例如,5 + 3和(5).+(3)是等价的,也就是说: a 方法 b a.方法(b) 二者是等价的, 前者是后者的简写形式

    val sum1 = 5 + 3 //实际上调用了 (5).+(3)
    val sum2 = (5).+(3) //可以发现,写成方法调用的形式,和上面得到相同的结果
    i += 1  //将i递增 , 和Java不同,在Scala中并没有提供++和–操作符
    
Range
1 to 5		// Range(1, 2, 3, 4, 5)
1.to(5)		// Range(1, 2, 3, 4, 5)
1 until 5   // Range(1, 2, 3, 4) , 不包含区间终点5
1 to 10 by 2 // Range(1, 3, 5, 7, 9)  创建一个从1到10的数值序列,包含区间终点10,步长为2
打印语句
print("My name is:")
println("My name is:") 	// 实现换行的效果,要采用println语句
val i = 5;	val j = 8;
printf("My name is %s. I hava %d apples and %d eggs.\n","Ziyu",i,j)

3. 读写文件

写文件
  • Scala需要使用java.io.PrintWriter实现把数据写入到文本文件。
import java.io.PrintWriter
val out = new PrintWriter("output.txt") // 只给出了文件名,并没有给出文件路径,则默认保存到当前工作目录
for (i <- 1 to 5) out.println(i)
out.close()
读文件
  • 可以使用Scala.io.Source的getLines方法实现对文件中所有行的读取。
import scala.io.Source
val inputFile = Source.fromFile("output.txt")
val lines = inputFile.getLines //返回的结果是一个迭代器
for (line <- lines) println(line)
  • 从屏幕上读取用户输入
import scala.io._
val br = new BufferedReader(new InputStreamReader(System.in)); 
val line = br.readLine()
// Scala2.11 后的版本 Console.readLine 已废弃,使用 scala.io.StdIn.readLine() 方法代替。
val line = StdIn.readLine()
println("your input is : " + line)
  • 本地读取
local_path = "file:///usr/local/spark/mycode/rdd/word.txt" // 注意,要加载本地文件,必须采用“file:///”开头的这种格式。
val lines = sc.textFile(local_path)
# lines是一个String类型的RDD
  • hdfs读取
val lines = sc.textFile("hdfs://localhost:9000/user/hadoop/word.txt") // hdfs://localhost:9000 加上 hdfs路径 ,注意有时候hdfs不一定用的9000端口
val lines = sc.textFile("/user/hadoop/word.txt")  // 默认从hdfs读取
val lines = sc.textFile("word.txt")
// 上面三条命令是完全等价的命令,只不过使用了不同的目录形式,你可以使用其中任意一条命令完成数据加载操作。

4. 控制结构

if条件表达式
val x = 6
if (x>0) {println("This is a positive number")
} else if { println("This is not a positive number")} 
else {println("This is a zero") }
while循环
var i = 9
while (i > 0) {
    i -= 1
    printf("i is %d\n",i)  }
for循环
// for (变量<-表达式) 语句块   其中,“变量<-表达式”被称为“生成器(generator)”
for (i <- 1 to 5) println(i)
for (i <- 1 to 5 if i%2==0) println(i)  // 守卫(guard)”的表达式  守卫( guards) (for loop 'if' conditions)
for (i <- 1 to 5; j <- 1 to 3) println(i*j)  
yield
for (i <- 1 to 5 if i%2==0) yield i  //  带有yield关键字的for循环,被称为“for推导式  计算得到新的集合,用于后续的其他处理。
/*  yield的用法总结
针对每一次 for 循环的迭代, yield 会产生一个值,被循环记录下来 (内部实现上,像是一个缓冲区).
当循环结束后, 会返回所有 yield 的值组成的集合.
返回集合的类型与被遍历的集合类型是一致的.			*/

二、数据结构

1. 数组、列表、元组

数组(Array)
// 包括定长数组和变长数组
val intValueArr = new Array[Int](3)  //声明一个长度为3的整型数组,每个数组元素初始化为0
intValueArr(0) = 12 //给第1个数组元素赋值为12 . 对数组元素的应用,是使用圆括号,而不是方括号
val intValueArr = Array(12,45,33)  //  简洁的数组声明和初始化方法
val myStrArr = Array("BigData","Hadoop","Spark")  
列表(List)
val intList = List(1,2,3)  // 列表有头部和尾部的概念
// intList.head来获取上面定义的列表的头部,值是1  intList.tail来获取上面定义的列表的尾部,值是List(2,3),可以看出,头部是一个元素,而尾部则仍然是一个列表。
val intList1 = List(1,2) ; val intList2 = List(3,4)
val intList3 = intList1:::intList2  // 用:::操作符连接得到新的列表
intList.sum  //  列表方法 实现求和
元组(tuple)
  • 元组是不同类型的值的聚集。元组和列表不同,列表中各个元素必须是相同类型,而元组可以包含不同类型的元素。
val tuple = ("BigData",2015,45.0)
println(tuple._1)	// BigData
println(tuple._3)   // 45.0

2.集合、映射、迭代器

集(set)
  • ”集”中的元素并不会记录元素的插入顺序,而是以“哈希”方法对元素的值进行组织
  • 集包括可变集和不可变集,缺省情况下创建的是不可变集,通常我们使用不可变集。
var mySet = Set("Hadoop","Spark")
mySet += "Scala"  //向mySet中增加新的元素  声明时,如果使用val,mySet += “Scala”执行时会报错,所以需要声明为var。
println(mySet.contains("Scala"))  // true
映射(Map)
  • 在Scala中,映射(Map)是一系列键值对的集合, 在映射中,所有的值,都可以通过键来获取。
val university = Map("WHU" -> "Wuhan University", "THU" -> "Tsinghua University","PKU"->"Peking University")
println(university("WHU"))  //  Wuhan University
university2("WHU") = "Wuhan University" //更新已有元素的值
university2 + = ("TJU"->"Tianjin University") //添加一个新元素
// 循环遍历映射   for ((k,v) <- 映射) 语句块
for ((k,v) <- university) printf("Code is : %s and name is: %s\n",k,v)  // ... Code is : PKU and name is: Peking University
for (k<-university.keys) println(k)
for (v<-university.values) println(v)  
迭代器(Iterator)
  • 在Scala中,迭代器(Iterator)不是一个集合,但是,提供了访问集合的一种方法。当构建一个集合需要很大的开销时(比如把一个文件的所有行都读取内存),迭代器就可以发挥很好的作用。
  • 迭代器包含两个基本操作:next和hasNext。next可以返回迭代器的下一个元素,hasNext用于检测是否还有下一个元素。
// 通常可以通过while循环或者for循环实现对迭代器的遍历。
val iter = Iterator("Hadoop","Spark","Scala")
while (iter.hasNext){ println(iter.next())} // 迭代器会移动到末尾,就不能再使用了,如果继续执行一次println(iter.next)就会报错。
// 上面代码中,使用iter.next和iter.next()都是可以的,但是,hasNext后面不能加括号。
for (elem <-iter) {println(elem) }

3.类、对象、继承、特质

class Counter {
    private var value = 0
    def increment(): Unit = { value += 1}  
    def increment(): Unit = value += 1 //去掉了大括号, 作为对比
    def increment() {value += 1} //去掉了返回值类型和等号,只保留大括号
    def current(): Int = {value}
}  // 使用new关键字来生成对象
cnt = new Counter //或者new Counter()
myCounter.increment() //或者也可以不用圆括号,写成myCounter.increments
  • increment()是方法,没有参数,冒号后面的Unit是表示返回值的类型,在Scala中不返回任何值,那么就用Unit表示,相当于Java中的void类型。
  • 方法的返回值,不需要靠return语句,方法里面的最后一个表达式的值就是方法的返回值,比如,上面current()方法里面只有一条语句“value”,那么,value的值就是该方法的返回值。ref
对象
  • 单例对象的定义和类的定义很相似,明显的区分是,用object关键字,而不是用class关键字。

  • Scala并没有提供Java那样的静态方法或静态字段,但是,可以采用object关键字实现单例对象,具备和Java静态方法同样的功能。

  • 每个Scala应用程序都必须从一个对象的main方法开始

object HelloWorld {
    def main(args: Array[String]){
        println("Hello, World!")
    } }
继承
abstract class Car{
   val carBrand: String 
     def info()
     def greeting() {println("Welcome to my car!")}
}
class BMWCar extends Car {
    override val carBrand = "BMW"
    def info() {printf("This is a %s car. It is expensive.\n", carBrand)}
    override def greeting() {println("Welcome to my BMW car!")}
}
  • Scala和Java一样,不允许类从多个超类继承
特质(trait)
  • 特质的定义和类的定义非常相似,有区别的是,特质定义使用关键字trait。一般 特质中没有方法体的方法,默认就是抽象方法。

  • 特质定义好以后,就可以使用extends或with关键字把特质混入类中。类似于java接口

  • 实际上,特质也可以包含具体实现,也就是说,特质中的字段和方法不一定要是抽象的。

4. 模式匹配

简单匹配
val colorNum = 1  // Scala的模式匹配最常用于match语句中。
val colorStr = colorNum match {
    case 1 => "red"
    case 2 => "green"
    case _ => "Not Allowed"   // 在模式匹配的case语句中,还可以使用变量。
    case unexpected => unexpected + " is Not Allowed"   } 
println(colorStr)
类型模式
for (elem <- List(9,12.3,"Spark","Hadoop",'Hello)){
    val str  = elem match{
        case i: Int => i + " is an int value."
        case d: Double => d + " is a double value."
        case "Spark"=> "Spark is found."
        case s: String => s + " is a string value."
        case _ => "This is an unexpected value."
    }	println(str)    }
Option类型
  • 标准类库中的Option类型用case类来表示那种可能存在、也可能不存在的值。
  • 一般而言,对于每种语言来说,都会有一个关键字来表示一个对象引用的是“无”,在Java中使用的是null。 scala使用Option类型
  • Option类包含一个子类Some,当存在可以被引用的值的时候,就可以使用Some来包含这个值,例如Some(“Hadoop”)。而None则被声明为一个对象,而不是一个类,表示没有值。
val books=Map("hadoop"->5,"spark"->10,"hbase"->7)
books.get("hadoop") //  res0: Option[Int] = Some(5)  这个键是存在的,可以取到值,并且取到的值会被包含在Some中返回
books.get("hive")  // res1: Option[Int] = None   这个键是不存在的,所以取到的值是None对象
books.get("hive").foreach(println)  // 屏幕上什么都没有显示,因为,foreach遍历遇到None的时候,什么也不做,自然不会执行println操作。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值