23篇大数据系列(二)scala基础知识全集(史上最全,建议收藏)(2)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)

正文

case class模式

构造器模式指的是,直接在case语句后面接类构造器,匹配的内容放置在构造器参数中。

object CaseClassPattern{  def main(args:Array[String]) :Unit = {  //定义一个Person实例  val p = new Person(“nyz”,27) //case class 模式  def constructorPattern(p : Person) = p match {     case Person(name,age) => “name =” + name + “,age =” + age     case _ => “Other”    }  }``}

模式守卫

为了让匹配更加具体,可以使用模式守卫,也就是在模式后面加上if判断语句。

object ConstantPattern{  def main(args:Array[String]) :Unit = {    //模式匹配结果作为函数返回值    def patternShow(x : Any) = x match { //模式守卫 case x if(x == 5) => “守卫” //通配符模式      case _ => “通配符”    }  }``}

Option匹配

在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值。

class OptionDemo { val map = Map ((“a”,18),(“b”,81))  //get方法返回的类型就是Option[Int] map.get(“b”) match { case some(x) => println(x) case None => println(“不存在”) }``}

五、Scala Trait(特质)

Scala Trait(特质) 相当于 Java 的接口,但实际上它比接口的功能强大。与接口不同的是,它还可以定义属性和方法的实现。

一般情况下Scala的类只能够继承单一父类,但可以使用with关键字混入多个 Trait(特质) 。不过,如果一个scala类没有父类,那么它混入的第一个特质需要使用extends关键字,之后混入的特质使用with关键字。

Trait(特质) 定义的方式与类相似,但它使用的关键字是 trait,如下所示:

trait Equal { def isEqual(x: Any): Boolean def isNotEqual(x: Any): Boolean = !isEqual(x)``}

以上特质(Equal)由两个方法组成:isEqual 和 isNotEqual。isEqual 方法没有定义方法的实现,isNotEqual定义了方法的实现。子类继承特质可以实现未被实现的方法。

以下演示了特质的完整实例:

trait Equal { def isEqual(x: Any): Boolean def isNotEqual(x: Any): Boolean = !isEqual(x)``}`

class Point(xc: Int, yc: Int) extends Equal { val x: Int = xc val y: Int = yc def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == x``}

object Test { def main(args: Array[String]) { val p1 = new Point(2, 3) val p2 = new Point(2, 4) val p3 = new Point(3, 3)

println(p1.isNotEqual(p2)) println(p1.isNotEqual(p3)) println(p1.isNotEqual(2)) `}``}

执行以上代码,输出结果为:

$ scalac Test.scala $ scala -cp . Test``false``true``true

六、集合操作

常用集合

通过下面的代码,可以了解常用集合的创建方式

// 定义整型 List,其元素以线性方式存储,可以存放重复对象。``val x = List(1,2,3,4)

// 定义 Set,其对象不按特定的方式排序,并且没有重复对象。``val x = Set(1,3,5,7)

// 定义 Map,把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。``val x = Map("one" -> 1, "two" -> 2, "three" -> 3)

// 创建两个不同类型元素的元组,元组是不同类型的值的集合``val x = (10, "Bigdata")

// 定义 Option,表示有可能包含值的容器,也可能不包含值。``val x:Option[Int] = Some(5)

集合函数

工作中操作 Scala 集合时,一般会进行两类操作:转换操作(transformation )和行动操作(action)。第一种操作类型将集合转换为另一个集合,第二种操作类型返回某些类型的值。

1)最大值和最小值

先从行动函数开始。在序列中查找最大或最小值是一个极常见的需求。

先看一下简单的例子。

val numbers = Seq(11, 2, 5, 1, 6, 3, 9) ``numbers.max //11 numbers.min //1

对于这种简单数据集合,Scala的函数式特性显露无疑,如此简单的取到了最大值和最小值。再来看一个数据集合复杂的例子。

case class Book(title: String, pages: Int) val books = Seq( Book(“Future of Scala developers”, 85), Book(“Parallel algorithms”, 240), Book(“Object Oriented Programming”, 130), Book(“Mobile Development”, 495))` `//下面代码返回Book(Mobile Development,495)books.maxBy(book => book.pages) //下面代码返回Book(Future of Scala developers,85)``books.minBy(book => book.pages)

minBy & maxBy方法解决了复杂数据的问题。

2)筛选-Filter

对集合进行过滤,返回满足条件的元素的新集合,比如过滤一组数据中的偶数。

val numbers = Seq(1,2,3,4,5,6,7,8,9,10) numbers.filter(n => n % 2 == 0)``//上面返回Seq(2,4,6,8,10)

获取页数大于300页的书。

val books = Seq( Book(“Future of Scala developers”, 85), Book(“Parallel algorithms”, 240), Book(“Object Oriented Programming”, 130), Book(“Mobile Development”, 495)``)`

`books.filter(book => book.pages >= 300)``//上面返回Seq(Book(“Mobile Development”, 495))

还有一个与 filter类似的方法是 filterNot,也就是筛选出不满足条件的对象。

3)Flatten

它的作用是将多个集合展开,组成一个新的集合,举例说明。

val abcd = Seq(‘a’, ‘b’, ‘c’, ‘d’)val efgj = Seq('e', 'f', 'g', 'h')val ijkl = Seq(‘i’, ‘j’, ‘k’, ‘l’)val mnop = Seq('m', 'n', 'o', 'p')val qrst = Seq(‘q’, ‘r’, ‘s’, ‘t’)val uvwx = Seq('u', 'v', 'w', 'x')val yz = Seq(‘y’, ‘z’) val alphabet = Seq(abcd, efgj, ijkl, mnop, qrst, uvwx, yz)`

`alphabet.flatten

执行后返回下面的集合:

List(‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’)

4)集合运算函数

集合运算即差集、交集和并集操作。

val num1 = Seq(1, 2, 3, 4, 5, 6)``val num2 = Seq(4, 5, 6, 7, 8, 9) //返回List(1, 2, 3)``num1.diff(num2) //返回List(4, 5, 6)``num1.intersect(num2) //返回List(1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9)``num1.union(num2)

//合并后再去重,返回List(1, 2, 3, 4, 5, 6, 7, 8, 9)``num1.union(num2).distinct

5)map函数

map 函数的逻辑是遍历集合并对每个元素调用传入的函数进行处理。

val numbers = Seq(1,2,3,4,5,6) //返回List(2, 4, 6, 8, 10, 12)``numbers.map(n => n * 2) val chars = Seq('a', 'b', 'c', 'd') //返回List(A, B, C, D)``chars.map(ch => ch.toUpper)

6)flatMap

它将map & flatten组合起来,请看下面的操作。

val abcd = Seq(‘a’, ‘b’, ‘c’, ‘d’) //List(A, a, B, b, C, c, D, d)``abcd.flatMap(ch => List(ch.toUpper, ch))

从结果可以看出来是先做的map,然后做的flatten

7)forall & exists

forall是对整个集合做判断,当集合中的所有元素都满足条件时,返回true。而exists则是只要有一个元素满足条件就返回true。

val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2) //返回turenumbers.forall(n => n < 10)` `//返回falsenumbers.forall(n => n > 5)`

`//返回true``numbers.exists(n => n > 5)

七、读取数据源

读取外部数据源是开发中很常见的需求,如在程序中读取外部配置文件并解析,获取相应的执行参数。这里只针对scala如何通过Source类读取数据源进行简单介绍。

import scala.io.Source object ReadFile { //读取ClasPath下的配置文件 val file = Source.fromInputStream(this.getClass.getClassLoader.getResourceAsStream(“app.conf”))`

//一行一行读取文件,getLines()表示读取文件所有行 def readLine: Unit ={ for(line <- file.getLines()){ println(line) } } //读取网络上的内容 def readNetwork: Unit ={ val file = Source.fromURL("http://www.baidu.com") for(line <- file.getLines()){ println(line) } }

//读取给定的字符串-多用于调试 val source = Source.fromString("test") `}

八、隐式转换

隐式转换是Scala中一种非常有特色的功能,是其他编程语言所不具有的,可以实现将某种类型的对象转换为另一种类型的对象。数据分析工作中,最常使用到的就是java和scala集合之间的互相转换,转换以后就可以调用另一种类型的方法。scala提供了scala.collection.JavaConversions类,只要引入此类中相应的隐式转化方法,在程序中就可以用相应的类型来代替要求的类型。

如通过以下转换,scala.collection.mutable.Buffer自动转换成了java.util.List。

import scala.collection.JavaConversions.bufferAsJavaList``scala.collection.mutable.Buffer => java.util.List

同样,java.util.List也可以转换成scala.collection.mutable.Buffer。

import scala.collection.JavaConversions.asScalaBuffer``java.util.List => scala.collection.mutable.Buffer

所有可能的转换汇总如下,双向箭头表示可互相转换,单箭头则表示只有左边可转换到右边。

import scala.collection.JavaConversions._

scala.collection.Iterable <=> java.lang.Iterable``scala.collection.Iterable <=> java.util.Collection``scala.collection.Iterator <=> java.util.{ Iterator, Enumeration }``scala.collection.mutable.Buffer <=> java.util.List``scala.collection.mutable.Set <=> java.util.Set``scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }``scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap

scala.collection.Seq => java.util.List``scala.collection.mutable.Seq => java.util.List``scala.collection.Set => java.util.Set``scala.collection.Map => java.util.Map``java.util.Properties   => scala.collection.mutable.Map[String, String]

隐式参数

所谓隐式参数,指的是在函数或者方法中,定义使用implicit修饰的参数。当调用该函数或方法时,scala会尝试在变量作用域中找到一个与指定类型相匹配的使用implicit修饰的对象,即隐式值,注入到函数参数中函数体使用。示例如下:

class SayHello{ def write(content:String) = println(content)}implicit val sayHello=new SayHello`

def saySomething(name:String)(implicit sayHello:SayHello){ sayHello.write("Hello," + name)``}

saySomething("Scala")

`//打印 Hello,Scala

值得注意的是,隐式参数是根据类型匹配的,因此作用域中不能同时出现两个相同类型的隐式变量,否则编译时会抛出隐式变量模糊的异常。

九、正则匹配

正则的概念、作用和规则都在上一篇《大数据分析工程师入门–1.Java基础》中已经完整的讲述了,这里将通过示例来讲解下在scala中正则相关代码怎么写:

定义

val TEST_REGEX = “home\(classification|foundation|my_tv)\[0-9-]{0,2}([a-z_]*)”.r

使用

//path是用来匹配的字符串``TEST_REGEX findFirstMatchIn path match { case Some(p) => { //获取TEST_REGEX中的第一个括号里正则片段匹配到的内容 launcher_area_code = p.group(1) //获取TEST_REGEX中的第二个括号里正则片段匹配到的内容 launcher_location_code = p.group(2) }``}

十、异常处理

学习过Java的同学对异常一定并不陌生,异常通常是程序执行过程中遇到问题时,用来打断程序执行的重要方式。关于异常处理的注意事项,在上一讲《大数据分析工程师入门–1.Java基础》里已经讲过了,这里就不再赘述了。我们重点来讲下scala和java在异常这个特性的设计上的不同。

1. 捕获异常的方式略有不同

java中是通过多个catch子句来捕获不同类型的异常,而在scala中是通过一个catch子句,加上模式匹配的类型匹配方式来捕获不同类型的异常。如下图所示:

2.scala没有checked异常

在java中,非运行时异常在编译期是会被强制检查的,要么写try…catch…处理,要么使用throws关键字,将异常抛给调用者处理。而在scala中,更推崇通过使用函数式结构和强类型来减少对异常及其处理的依赖。因此scala不支持检查型异常(checked exception)。

当使用scala调用java类库时,scala会把java代码中声明的异常,转换为非检查型异常。

3.scala在throw异常时是有返回值的

在scala的设计中,所有表达式都是有返回值的。那么,自然throw表达式也不例外,throw表达式的返回值为Nothing。由于Nothing类型是所有类型的子类型,因此throw表达式可以出现在任意位置,而不会影响到类型的推断。

十一、类型层级

在scala中,所有的值都是有类型的,包括数值型值和函数,比java更加彻底地贯彻了万物皆对象的理念。因此,scala有一套自己的类型层级,如下图所示:

(图片来自于网络)

如图中所示,scala的顶级类是Any,下面包含两个子类,AnyVal和AnyRef,其中AnyVal是所有值类型的父类,其中包含一个特殊的值Unit;而AnyRef是所有引用类型的父类,所有java类型和非值类型的scala类型都是它的子类。其中,有两个比较特殊的底层子类型,一个是Null,它是所有引用类型的子类型,可以赋给任何引用类型变量;另一个是Nothing,它是所有类型的子类,因此既可以赋给引用类型变量,也可以赋给值类型变量。

十二、基本数值类型转换

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

2703631.png)

(图片来自于网络)

如图中所示,scala的顶级类是Any,下面包含两个子类,AnyVal和AnyRef,其中AnyVal是所有值类型的父类,其中包含一个特殊的值Unit;而AnyRef是所有引用类型的父类,所有java类型和非值类型的scala类型都是它的子类。其中,有两个比较特殊的底层子类型,一个是Null,它是所有引用类型的子类型,可以赋给任何引用类型变量;另一个是Nothing,它是所有类型的子类,因此既可以赋给引用类型变量,也可以赋给值类型变量。

十二、基本数值类型转换

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)

[外链图片转存中…(img-Jfmr8ZMx-1713110890398)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!