windows安装Scala,配置环境变量
官网下载scala2.11
https://www.scala-lang.org/download/all.html
https://www.scala-lang.org/download/2.11.0.html
https://downloads.lightbend.com/scala/2.11.0/scala-2.11.0.msi
下载好后安装。双击msi包安装,记住安装的路径(注意:这里建议将Scala安装到纯英文没有空格和特殊符号的路径下。避免后期使用Scala版本出现问题。)
配置环境变量(和配置jdk一样),添加环境变量SCALA_HOME
SCALA_HOME=安装路径
在Path变量追加配置
%SCALA_HOME%\bin
打开cmd,输入:scala -version 看是否显示版本号,确定是否安装成功
scala官网文档地址
中文文档
https://docs.scala-lang.org/zh-cn/tour/tour-of-scala.html
官方网站
https://docs.scala-lang.org/
在IDEA安装scala插件
在plugin中搜索scala插件安装
创建scala项目
选择Scala,再选择IDEA,
再配置Project name、Project location、JDK、
Scala SDK(选择对于版本,没有时选择再在本地的安装目录)
创建scala主函数
1.object表示一个伴生对象(相当于一个对象)
2.HelloWorld是对象的名字
3.def表示声明一个方法
4.main表示程序入口
5.args:Array[String] 表示形参,和go语言差不多,把参数写前面,类型写在后面
6.Unit表示返回值为空(类似Java中的void)
object HelloWorld {
def main(args: Array[String]): Unit = {
print("Hello World")
}
}
变量的使用
object VarDemo {
def main(args: Array[String]): Unit = {
var a:Int = 10
var b:String = "hello"
var c:Boolean = false
var d:Double = 10.0
var f:Float = 10.1f
println(s"${a}${b}")
}
}
现代编译器,都是动态的,很多编译器都会进行自由化的逃逸分析
注意事项:
1.声明变量时,类型可以省略,编译器会自动推导,比如var a:Int = 10可以把:Int简写,这样做,自己本身还是会自动转为强类型,类似println(a.isInstanceOf[Int])
2.声明变量我们有2种方式,var或者val,var修饰的变量可以改变,val修饰的变量不可以改变,如果不需要改变,我们推荐使用val,因为线程安全,效率高
var a=10
a=""//可以
val b=10
b=""//不可以
3.变量不能不给初始值
var a //不可以
程序运算符
1.程序+的使用
(1)、左右都是数值,做加法
(2)、左右有一方是字符串,做拼接运算
数据类型
1.在Scala中,数据类型都是对象
2.Scala数据类型分为AnyVal(值类型)和AnyRef(引用类型)
无论值类型,和引用类型,都是对象
在scala中,使用Any作为总根
AnyVal是一个分支:Double,Float,Long,Int,Short,Byte,Boolean,Char,StringOps,Unit
AnyRef是一个分支:里面有Scala集合,所有Java类,Null,Nothing和其他Scala类
整型
1.Scala整型不受OS影响,保证可移植性
2.常量/字面量默认Int型,声明Long型必须加l或者L
3.Scala程序中变量常声明为Int型,除非不足以表示大数,才是用Long
Byte Short Int Long分别1,2,4,8字节,和Java一样
浮点型
1.浮点型有固定的范围和长度,不受OS影响
2.默认Double型,声明Float必须加
3.浮点型可直接表示也可科学计数法
4.通常情况下Double比Float更精确,小数点约后7位
字符型
1.Char字符是2个字节
2.允许转义符号,转化为常量
3.可以直接赋值一个整数
4.Char类型可以运算,因为是Unicode编码
Boolean
true & false
Unit & Null & Nothing重点
1.我们把Unit进行返回打印,进行测试,打印()
def main(args: Array[String]): Unit = {
var res=sayHello()
println(res)
}
def sayHello():Unit={
}
输出:()
2.关于Null
val dog:Dog=null
val ch:Char=null
比较上述两句代码,我们发现,只有Dog不报错,证明,只有AnyRef分支的是可以用null修饰
3.关于Nothing
Nothing是Scala类层级的最低端,是任何其他类型的子类型,当一个函数没有确定返回值,可以返回Nothing
for循环结构
获取1~9的集合
val seqs = 1 until 10
输出:Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
var seqs = 1 to 9
输出:Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
遍历集合seqs
for(i <- seqs if(i%2==0)){
print(i)
}
输出2468
打印99乘法表
for(i <- 1 to 9){
for (j <- 1 to 9){
if(j<=i) print(s"$i * $j = ${i*j}\t")
if(j == i ) println()
}
}
更简单的打印99乘法表
for(i <- 1 to 9;j <- 1 to 9 if(j<=i)){
if(j<=i) print(s"$i * $j = ${i*j}\t")
if(j == i ) println()
}
方法函数
无参、无返回值
def fun01() {
println("hello world")
}
有参、无返回值
def fun02(a: Int): Unit = {
println(a)
}
有参、有返回值
def fun03(a: Int): Int = {
3
}
递归函数(有参、有返回值)
def fun04(num: Int): Int = {
if (num == 1) {
num
} else {
num * fun04(num - 1)
}
}
调用递归函数
val i: Int = fun04(4)
默认值函数
def fun05(a: Int = 8, b: String = "abc"): Unit = {
println(s"$a\t$b")
}
调用可使用
fun05() 默认值
fun05(1,"a") 给定值
fun05(22) 第一个参数值
fun05(b = "ooxx") 第二个参数值
匿名函数
//函数:
//1,签名 :(Int,Int)=>Int : (参数类型列表)=> 返回值类型
//2,匿名函数: (a:Int,b:Int) => { a+b } :(参数实现列表)=> 函数体
var xx: Int = 3
var yy: (Int, Int) => Int = (a: Int, b: Int) => {a + b}
调用 val w: Int = yy(3, 4)
嵌套函数
def fun06(name: String): Unit = {
def fun05(): Unit = {
println(name)
}
}
调用 fun06("hello")
偏应用函数
def fun07(date: Date, tp: String, msg: String): Unit = {
println(s"$date\t$tp\t$msg")
}
调用
fun07(new Date(), "info", "ok")
偏应用函数扩展,第二个参数固定值
var info = fun07(_: Date, "info", _: String)
var error = fun07(_: Date, "error", _: String)
info(new Date, "ok")
error(new Date, "error...")
可变参数
约定:类型需要一致(Int*)
def fun08(a: Int*): Unit = {
for (e <- a) {
println(e)
}
// 遍历集合的几种写法
// def foreach[U](f: A => U): Unit // 语法
// a.foreach( (x:Int)=>{println(x)} ) // 实现
// a.foreach( println(_) ) // 更简单实现
a.foreach(println) // 最简单实现
}
调用函数
fun08(2)
fun08(1, 2, 3, 4, 5, 6)
高阶函数
//函数作为参数,函数作为返回值
//函数f作为参数
def computer(a: Int, b: Int, f: (Int, Int) => Int): Unit = {
val res: Int = f(a, b)
println(res)
}
computer(3, 8, (x: Int, y: Int) => {x + y})
computer(3, 8, (x: Int, y: Int) => {x * y})
computer(3, 8, _ * _) // 最简单写法
//函数作为返回值:
def factory(i: String): (Int, Int) => Int = {
def plus(x: Int, y: Int): Int = {x + y}
if (i.equals("+")) {
plus
} else {
(x: Int, y: Int) => {x * y}
}
}
调用 computer(3, 8, factory("-"))
柯里化
// 解决同时传递多个类型的数组问题
def fun09(a: Int)(b: Int)(c: String): Unit = {
println(s"$a\t$b\t$c")
}
调用fun09(3)(8)("sdfsdf")
输出3 8 sdfsdf
def fun10(a: Int*)(b: String*): Unit = {
a.foreach(println)
b.foreach(println)
}
调用fun10(1, 2, 3)("sdfs", "sss")
输出
1 2 3
sdfs sss
*.方法
// 方法没参数的情况下,括号()可以省略
//方法不想执行,赋值给一个引用 方法名+空格+下划线
val funa = ooxx // 此处会执行方法
println(funa)
val func = ooxx _ // 此处不会执行方法
func() // 此处调用会执行方法
//语法 -> 编译器 -> 字节码 <- jvm规则
//编译器,衔接 人 与 机器
//java 中 +: 关键字
//scala中+: 方法/函数
//scala语法中,没有基本类型,所以你写一个数字 3 编辑器/语法,其实是把 3 看待成Int这个对象
C、scala、java、python对比
编译型 C语言 《 贼快
解释型 python语言 《 贼慢
JAVA:其实不值钱,最值钱的是JVM
JAVA:解释型,编译过程,编译会把类型变成二进制,运行比python快
JVM:为什么值钱 是C写的,更快【字节码(二进制) >JVM(堆/堆外(二进制))< kernel(mmap,sendfile) 】
集合
直接使用java集合
//你是一个javacoder
val listJava = new util.LinkedList[String]()
listJava.add("hello")
数组
//Java中泛型是<> scala中是[],所以数组用(n)
//val 约等于 final 不可变描述的是val指定的引用的值(值:字面值,地址)
val arr01 = Array[Int](1,2,3,4) // 数组初始化
arr01(1)=99 // 修改数据元素值
println(arr01(0)) // 打印数组数据
for (elem <- arr01) { // for循环输出数组元素
println(elem)
}
arr01.foreach(println) //更简单的遍历元素
集合List
//scala中collections中有个2个包:immutable、mutable,默认的是不可变的immutable
val list01 = List(1,2,3,4,5,4,3,2,1) // 不可变的集合
for (elem <- list01) {
println(elem)
}
list01.foreach(println)
val list02 = new ListBuffer[Int]() // 可变的集合
list02.+=(33)
list02.+=(34)
list02.+=(35)
list02.foreach(println) // 遍历打印集合元素
集合set
val set01: Set[Int] = Set(1,2,3,4,2,1) // 不可变的集合
for (elem <- set01) {
println(elem)
}
set01.foreach(println)
import scala.collection.mutable.Set // 指出包名时,在下面的Set都是引用的这个包下面的
val set02: mutable.Set[Int] = Set(11,22,33,44,11)
set02.add(88)
set02.foreach(println)
val set03: Predef.Set[Int] = scala.collection.immutable.Set(33,44,22,11) // 直接在集合上加包名来指定引用的对象
Tuple集合
val t2 = new Tuple2(11,"sdfsdf") //2元素的Tuple2 在scala描绘的是K,V
val t2 = (11,"sdfsdf") //2元素的Tuple2 在scala描绘的是K,V
val t3 = Tuple3(22,"sdfsdf",'s')
val t4: (Int, Int, Int, Int) = (1,2,3,4)
val t22: ((Int, Int) => Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = ( (a:Int,b:Int)=>a+b+8 ,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,1,2,3,4)
println(t2._1) //取元素
println(t4._3)
//val i: Int = t22._1(8)
//println(i)
println(t22._1)
val tIter: Iterator[Any] = t22.productIterator //迭代器遍历元素
while(tIter.hasNext){
println(tIter.next())
}
集合Map
val map01: Map[String, Int] = Map( ("a",33) , "b"->22 ,("c",3434),("a",3333) )
val keys: Iterable[String] = map01.keys
//option: none some
println(map01.get("a").get) 输出33
//println(map01.get("w").get) null指针异常
println(map01.get("a").getOrElse("hello world")) // 获取值
println(map01.get("w").getOrElse("hello world")) // 获取值
for (elem <- keys) {
println(s"key: $elem value: ${map01.get(elem).get}")
}
val map02: mutable.Map[String, Int] = scala.collection.mutable.Map(("a",11),("b",22)) //创建可变的集合
map02.put("c",22)
艺术
val list = List(1,2,3,4,5,6)
list.foreach(println)
val listMap: List[Int] = list.map( (x:Int) => x+10 ) //集合每个元素都加10
listMap.foreach(println)
val listMap02: List[Int] = list.map( _*10 ) //集合每个元素都乘10
list.foreach(println)
listMap02.foreach(println)
艺术-升华
val listStr = List(
"hello world",
"hello msb",
"good idea"
)
val flatMap= listStr.flatMap( (x:String)=> x.split(" ") ) //把集合的数据再分割生成新的集合
flatMap.foreach(println)
val mapList = flatMap.map( (_,1) ) // 生成map集合,键为key值为1
mapList.foreach(println)
//以上代码有什么问题吗? 内存扩大了N倍,每一步计算内存都留有对象数据;有没有什么现成的技术解决数据计算中间状态占用内存这一问题~?
//迭代器模式!!!!!
艺术-再-升华
//基于迭代器的原码分析
val iter: Iterator[String] = listStr.iterator //什么是迭代器,为什么会有迭代器模式? 迭代器里不存数据!
val iterFlatMap= iter.flatMap( (x:String)=> x.split(" ") )
//iterFlatMap.foreach(println)
val iterMapList = iterFlatMap.map( (_,1) )
while(iterMapList.hasNext){
val tuple: (String, Int) = iterMapList.next()
println(tuple)
}
类的多继承
object test {
trait A{
def a(): Unit ={
println("a method")
}
}
trait B{
def b(): Unit ={
println("b method")
}
def c();
}
class Persion(name:String) extends A with B{
def d(): Unit ={
print(s"d method:$name")
}
override def c(): Unit = {
println("c method")
}
}
def main(args: Array[String]): Unit = {
val p = new Persion("张三")
p.a()
p.b()
p.c()
p.d()
}
}
对象的便捷比较关键字case
case class Dog(name:String,age:Int){
}
object Test {
def main(args: Array[String]): Unit = {
val dog1 = Dog("hsq",18)
val dog2 = Dog("hsq",18)
println(dog1.equals(dog2))
println(dog1 == dog2)
}
}
输出
true
true
match的使用,类似swtich
object Test {
def main(args: Array[String]): Unit = {
val tup: (Double, Int, String, Boolean, Int) = (1.0,88,"abc",false,55)
val iter: Iterator[Any] = tup.productIterator
val res: Iterator[Unit] = iter.map(
(x) => {
x match {
// 在匹配到一个case后自动返回
// 迭代器不调用时不会执行此方法
case 1 => println(s"$x...is 1")
case 88 => println(s"$x ...is 88")
case false => println(s"$x...is false")
case w: Int if w > 50 => println(s"$w...is > 50")
case _ => println("wo ye bu zhi dao sha lei xing ")
}
}
)
while(res.hasNext) println(res.next())
}
}
输出
1.0...is 1
()
88 ...is 88
()
wo ye bu zhi dao sha lei xing
()
false...is false
()
55...is > 50
()
偏函数的使用
object Test {
def main(args: Array[String]): Unit = {
// 偏函数入参任意类型,出参字符串
def ff:PartialFunction[Any,String] ={
case "hello" => "val is hello"
case x:Int => s"$x...is int"
case _ => "none"
}
println(ff(44))
println(ff("hello"))
println(ff("hi"))
}
}
输出
44...is int
val is hello
none
隐式转换scala的编译器处理流程
// 1,scala编译器发现 list.foreach(println) 有bug
// 2,去寻找有没有implicit 定义的方法,且方法的参数正好是list的类型!!!
// 3,编译期:完成你曾经人类:
// val xx = new XXX(list)
// xx.foreach(println)
// 编译器帮把代码改写了
隐式方法转换
import java.util
object Test {
def main(args: Array[String]): Unit = {
val listLinked = new util.LinkedList[Int]()
listLinked.add(1)
listLinked.add(2)
//隐式转换方法,在java List集合上添加foreach方法
implicit def abcd[T](list:util.LinkedList[T]) ={
val iter: util.Iterator[T] = list.iterator()
new XXX(iter)
}
listLinked.foreach(println)
}
}
class XXX[T](list:util.Iterator[T]){
def foreach( f:(T)=>Unit): Unit ={
while(list.hasNext) f(list.next())
}
}
输出
1
2
隐式类转换
import java.util
object Test {
def main(args: Array[String]): Unit = {
val list = new util.LinkedList[Int]()
list.add(1)
list.add(2)
//隐式转换类
implicit class KKK[T](list: util.LinkedList[T]) {
def foreach(f: (T) => Unit): Unit = {
val iter: util.Iterator[T] = list.iterator()
while (iter.hasNext) f(iter.next())
}
}
list.foreach(println)
}
}
输出
1
2
隐式参数转换
object Test {
def main(args: Array[String]): Unit = {
implicit val sdfsdfsd:String = "lisi"
// 隐式转换参数
// 带关键字implicit的参数可以不传值,会寻找定义的相同类型的implicit常量参数值
// 带关键字implicit的参数列表,要不全部传值,要不全部不传值,但可以通过柯里化的形式写参数
def xx(age:Int)(implicit name:String): Unit ={
println(name+" "+age)
}
xx(66)("jkljkl")
xx(33)
}
}
输出
jkljkl 66
lisi 33
用scala、java 两门语言书写一段spark的wordcount程序
普通项目转maven过程
点击项目名右键-->选择Add Frameworks Support-->勾选maven-->点击OK
基于maven的方式开发spark
spark/MR 他们都可以集群分布式运行,也可以单击本地运行
统计的数据文件内容:
hello world
hello msb
hello spark
good spark
引入spark依赖包
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.3.4</version>
</dependency>
使用scala语言统计(非简写)
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object WordCountScala {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setAppName("wordcount")
conf.setMaster("local") //单击本地运行
val sc = new SparkContext(conf)
val fileRDD: RDD[String] = sc.textFile("data/testdata.txt")
//hello world
val words: RDD[String] = fileRDD.flatMap((x:String)=>{x.split(" ")})
//hello
//world
val pairWord: RDD[(String, Int)] = words.map((x:String)=>{new Tuple2(x,1)})
//(hello,1)
//(hello,1)
//(world,1)
val res: RDD[(String, Int)] = pairWord.reduceByKey( (x:Int,y:Int)=>{x+y} )
//X:oldValue Y:value
//(hello,2) -> (2,1)
//(world,1) -> (1,1)
//(msb,2) -> (2,1)
res.foreach(println)
// 简单写法,仅需要两行代码
// val fileRDD: RDD[String] = sc.textFile("data/testdata.txt")
// fileRDD.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).foreach(println)
}
}
输出
(spark,2)
(hello,3)
(msb,1)
(good,1)
(world,1)
使用scala语言统计(简写)
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object WordCountScala2 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("scala app").setMaster("local")
val sc = new SparkContext(conf)
val fileRdd: RDD[String] = sc.textFile("data/testdata.txt")
// 仅为一处使用参数时,可以简写使用_代替参数
fileRdd.flatMap(_.split(" ")).map(Tuple2(_,1)).reduceByKey(_+_).foreach(println)
}
}
输出
(spark,2)
(hello,3)
(msb,1)
(good,1)
(world,1)
使用java语言统计(非简写)
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
import scala.Tuple2;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Iterator;
public class WordCountJava {
public static void main(String[] args) throws FileNotFoundException {
SparkConf conf = new SparkConf();
conf.setAppName("java-wordcount");
conf.setMaster("local");
JavaSparkContext jsc = new JavaSparkContext(conf);
JavaRDD<String> fileRDD = jsc.textFile("data/testdata.txt");
JavaRDD<String> words = fileRDD.flatMap(new FlatMapFunction<String, String>() {
public Iterator<String> call(String line) throws Exception {
return Arrays.asList(line.split(" ")).iterator();
}
});
JavaPairRDD<String, Integer> pairWord = words.mapToPair(new PairFunction<String, String, Integer>() {
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
});
JavaPairRDD<String, Integer> res = pairWord.reduceByKey(new Function2<Integer, Integer, Integer>() {
public Integer call(Integer oldV, Integer v) throws Exception {
return oldV + v;
}
});
res.foreach(new VoidFunction<Tuple2<String, Integer>>() {
public void call(Tuple2<String, Integer> value) throws Exception {
System.out.println(value._1+"\t"+value._2);
}
});
}
}
输出
spark 2
hello 3
msb 1
good 1
world 1
使用java语言统计(简写)
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import scala.Tuple2;
import java.io.FileNotFoundException;
import java.util.Arrays;
public class WordCountJava {
public static void main(String[] args) throws FileNotFoundException {
SparkConf conf = new SparkConf().setAppName("java-wordcount").setMaster("local");
JavaSparkContext jsc = new JavaSparkContext(conf);
JavaRDD<String> fileRDD = jsc.textFile("data/testdata.txt");
fileRDD.flatMap(line -> Arrays.asList(line.split(" ")).iterator())
.mapToPair(word -> new Tuple2<String, Integer>(word, 1))
.reduceByKey((oldV, v) -> oldV + v)
.foreach(value ->System.out.println(value._1+"\t"+value._2));
}
}
输出
spark 2
hello 3
msb 1
good 1
world 1