Scala

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中的voidobject 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或者valvar修饰的变量可以改变,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是一个分支:DoubleFloatLongIntShortByteBooleanChar,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.通常情况下DoubleFloat更精确,小数点约后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
posted @   rbcd  阅读(41)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示