函数式编程:
wordcount 案列
import java.io.{File, PrintWriter}
import scala.io.Source
/**
-
Author itcast
-
Date 2019/7/18 11:31
-
Desc 演示初级版WordCount
*/
object WordCountDemo2 {
def main(args: Array[String]): Unit = {
//需求读取D:\授课\190411\Scala\资料\data文件夹下的所有文件,并进行单词技术
//1.读取文件夹下的所有文件
val dir = new File(“D:\授课\190411\Scala\资料\data”)
val files: Array[File] = dir.listFiles()
//2.遍历文件夹下的文件并读取文件内容
val filesResult: Array[Map[String, Int]] = files.map(file => {
//3.读取文件中的所有行
val lines: Iterator[String] = Source.fromFile(file).getLines()
//4.对每一行按空格切分
//切分的结果是每一行一个数组组成的一个大的集合,所以要进行flatten压平,所以可以使用flatMap一步搞定
val words: Iterator[String] = lines.flatMap(.split(" "))
//5.对每一个单词记为1
//val wordAndOnes: Iterator[(String, Int)] = words.map(word => (word,1))
//[(hadoop, 1),(hadoop, 1),(hive, 1)…]
val wordAndOnes: List[(String, Int)] = words.map((, 1)).toList
//6.分组
//map(hadoop->[(hadoop, 1),(hadoop, 1)],hive->[(hive, 1)]…)
val wordAndTuples: Map[String, List[(String, Int)]] = wordAndOnes.groupBy(.1)
//7.组内计数
val wordAndCount: Map[String, Int] = wordAndTuples.mapValues(.length)
wordAndCount
})
//[(hadoop, 2),(hadoop, 2),(hadoop, 2),(hive,1),(hive,1),(hive,1)…]
val wordAndTempCount: Array[(String, Int)] = filesResult.flatten
//Map[hadoop, Array[(hadoop, 2),(hadoop, 2),(hadoop, 2)]]
val wordAndTupleArrays: Map[String, Array[(String, Int)]] = wordAndTempCount.groupBy(.1)
//第1个:map中value 即数组
//第2个_:之前的累加值
//第3个_:元组
//第4个_:元组中的第2个元素
val result: Map[String, Int] = wordAndTupleArrays.mapValues(.foldLeft(0)(+_._2))
println(result)//写入文件
val writer = new PrintWriter(new File(“D:\授课\190411\Scala\资料\out\result.txt”))
for((k,v) <- result){
writer.println(k +":"+v)
}
writer.close()
println(“统计结束”)
}
}
面向对象
类的作用:对象的原型/图纸,本质上是对于事物的抽象描述
如: 描述电商网站的用户,可以抽象出一个User类,里面有用户的行为(收藏商品、下单、支付)和属性(姓名、年龄、账户、密码)
在Scala中,类并不用声明为public类型的(默认就是public)
Scala源文件中可以包含多个类,所有这些类都具有共有可见性
调用无参方法时,可以加(),也可以不加;如果方法定义中不带括号,那么调用时就不能带括号
●主构造器和辅助构造器
Scala中分为主构造器和辅助构造器:
主构造器:每个类都有,与类交织在一起,主构造器的参数直接放置类名后面,且主构造器会执行类定义中的所有语句。
辅助构造器:需要调用主构造器或者其他辅助构造器,就是方法
object
1.作为程序入口
在 Scala 中和Java一样也必须要有一个 main 方法作为程序的入口,而且必须定义在 object 中
2.作为工具类
在Scala中没有静态方法和静态字段,但是可以使用object来达到同样的目的。可以类比与Java中的工具类
3.作为伴生对象
●类比Java
在Java中,经常会有一些类,同时有实例成员又有静态成员。
●Scala中的伴生对象
在scala中,要实现类似的效果,可以使用伴生对象来实现。
一个class和object具有同样的名字。这个object称为伴生对象,这个class称为伴生类
- 伴生对象必须要和伴生类一样的名字
- 伴生对象和伴生类在同一个scala源文件中
- 伴生对象和伴生类最大特点是,可以相互访问,包括private属性
注意:如果某个成员的权限设置为private[this],表示只能在当前类中访问。伴生对象也不可以访问
抽象类
●抽象类、抽象方法和抽象字段
一个类中,如果含有一个抽象方法或抽象字段,就必须使用abstract将类声明为抽象类,该类是不可以被实例化的
如果在父类中,有某些方法无法立即实现,而需要依赖不同的子类来覆盖,重写实现不同的方法此时,可以将父类中的这些方法编写成只含有方法签名,不含方法体的形式,这种形式就叫做抽象方法
如果在父类中,定义了字段,但是没有给出初始值,则此字段为抽象字段
特质trait(接口)
★注意:
类可以使用extends关键字继承trait
注意不是 implement,而是extends ,在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends
Scala和Java一样不支持多继承类,但是支持多重继承 trait,使用 with 关键字即可
●在trait中定义抽象方法
在trait中可以定义抽象方法,类继承后,必须实现抽象方法,可以不使用 override 关键字,建议加上;
●在trait中定义抽象字段
在trait中trait也能定义抽象字段,继承trait的类,则必须覆盖抽象字段,提供具体的值
●在trait中定义具体方法
在trait中不仅可以定义抽象方法,还可以定义具体的方法
●在trait中定义具体字段
在trait中可以定义具体的字段,此时继承 trait 的子类就自动获得了 trait 中定义的字段
但是这种获取字段的方式与继承 class 的是不同的
如果是继承 class 获取的字段,实际上还是定义在父类中的
如果是继承 trait获取的字段,就直接被添加到子类中了
4.构造机制
trait也是有构造代码的,即在trait中,不包含在任何方法中的代码;
trait不能有构造器参数,每个trait都有一个无参数的构造器(只有空参构造是trait与类之间主要的差别)
继承了trait的子类,其构造机制如下:
-父类的构造函数先执行,即 class 类必须放在最左边;
-trait的构造代码后执行,多个trait从左向右依次执行;
-构造trait时,先构造父 trait,如果多个trait继承同一个父trait,则父trait只会构造一次;
-所有trait构造完毕之后,子类的构造函数最后执行。