一起重新开始学大数据-scala |
目录
scala简介
介绍:
Scala 是 Scalable Language 的简写,是一门多范式的编程语言
联邦理工学院洛桑(EPFL)的Martin Odersky于2001年基于Funnel的工作开始设计Scala。
Scala是把函数式编程思想和面向对象编程思想结合的一种编程语言。
大数据计算引擎Spark由Scala编写
特点:
特点 |
---|
Scala可拓展 |
面向对象 |
函数式编程 |
兼容JAVA |
类库调用 |
互操作 |
语法简洁 |
代码行短 |
类型推断 |
抽象控制 |
静态类型化 |
可检验 |
安全重构 |
支持并发控制 |
强计算能力 |
自定义其他控制结构 |
scala的OO、FP
-
在面向对象编程中(OO),我们把对象传来传去,那在函数式编程中,我们要做的是把函数传来传去,而这个,说成术语,我们把他叫做高阶函数。
-
在函数式编程中(FP),函数是基本单位,,他几乎被用作一切,包括最简单的计算,甚至连变量都被计算所取代。在函数式编程中,变量只是一个名称,而不是一个存储单元,这是函数式编程与传统的命令式编程最典型的不同之处。
基于jvm的语言
scala安装
第一种:官网下载http://www.scala-lang.org/
第二种:idea上下载插件,基于maven导包(File->Settings->Plugins->scala->download)
scala基础语法
一、准备工作
1、创建项目
创建maven项目然后在pom.xml导入scala依赖(刷新依赖,如果不能创建就关闭重新打开)
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.12</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.11.12</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-reflect</artifactId>
<version>2.11.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Java Compiler -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Scala Compiler -->
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
2.创建class类(正常主要创建对象,这里选择class)
二、CLASS、OBJECT、def
/ 不能定义静态方法
// 静态方法需要放在与之同名的object中,即它的伴生对象中
// 在class中主要关心定义 类的属性及类方法
class Demo1Scala {
// 不会在class中定义main方法
// def main(args: Array[String]): Unit = {
// println("helloWorld")
// }
}
/**
* 实际上就相当于 一个对象
* 里面的方法都是静态方法 可以直接通过Object的名字进行调用
* 如果object的类名跟class的类名相同时 就把这个object成为class的伴生对象
* 相当于单例模式创建出来的对象
*/
object Demo1Scala {
val id = 1
/**
* def 声明函数的关键字
* main 方法名
* args: Array[String] 参数名: 参数类型
* Unit 表示函数的返回值 相当于void
* {方法体}
*/
def main(args: Array[String]): Unit = {
println("object 中的 main方法")
// new Demo1ScalaClass().main(args)
Demo1Scala.func1()
println(Demo1Scala.id)
}
def func1() = {
println("func1")
}
}
***伴生对象和伴生类
伴生类中可以在域中直接使用类名方法的方式调用伴生对象中的方法
在main方法中:
1、使用伴生类直接建立一个示例,属性和方法只能是class域中的
2、使用伴生对象提供的实例,属性和方法只能是object域中的
3、伴生对象中定义apple方法可以不使用new来新建实例
三、变量
object Demo01Scala {
def main(args: Array[String]): Unit = {
/**
* 在scala中对于变量的修饰就两种
* val var
* val : 不可以进行修改 实际上不变的是引用不变
* var : 可以进行修改
*/
val a = 1 // 相当于java中的final
// a = 2 // 报错 因为由val修饰过的变量 不能进行修改
var b = 1
println(b)
b = 2
println(b)
val list = new util.ArrayList[String]()
list.add("a")
list.add("b")
list.add("c")
println(list)
val stu1 = new Demo4JavaStu("001", "张三", 20)
val lisi = new Demo5ScalaStu("001", "李四")
println(lisi._id)
}
}
四、数据类型、算术运算符、关系运算符、循环
数据类型
Byte 8bit的有符号数字,范围在-128 – 127
Short 16 bit有符号数字,范围在-32768 – 32767
Int 32 bit 有符号数字,范围 -2147483648 到 2147483647
Long 64 bit 有符号数字,范围-9223372036854775808 到 9223372036854775807
Float 32 bit IEEE 754 单精度浮点数
Double 64 bit IEEE 754 双精度浮点数
Char 16 bit Unicode字符. 范围 U+0000 到 U+FFFF
String 字符串
Boolean 布尔类型
Unit 表示无值,和其他语言中void等同
Null 空值或者空引用
Nothing 所有其他类型的子类型,表示没有值
Any 所有类型的超类,任何实例都属于Any类型
AnyRef 所有引用类型的超类
object Demo6Base {
def main(args: Array[String]): Unit = {
// 单行注释
/**
* 多行注释 一般用于文档
*/
// 变量 : 命名规范参考Java的,大小写字母、数字、下划线,不能以数字开头,不能关键字
// 可以分为两类: val var
// 一般情况下 能使用val的情况下尽量使用val
val a = 1 // val 修饰的变量 不可以进行修改(不可以重新赋值或者重新引用)
println(a)
// a = 0 // 不能修改 这是错误的
var b = 2 // var 修饰的变量 可以进行修改(重新赋值或者重新引用)
b = 3 // 这是可以的
// 变量的类型会自动推断
// 定义变量的时候实际上是可以指定类型的
val c: Int = 20
// 数据类型
val byte: Byte = 10
val short: Short = 100
val int: Int = 1000
val long: Long = 100000L
val float: Float = 1.1f
val double: Double = 1.2
val bool: Boolean = true
val bool2: Boolean = false
val char: Char = 'c'
// 引用类型
// scala中的String实际上是Java中的
// 在scala会给String加上很多新的方法(隐式转换)
val str: String = "abcdefg"
// 拼接字符串
val name = "张三"
val age = 20
val clazz = "文科一班"
// 直接加
val str3 = name + "," + age + "," + clazz
println(str3)
// 通过StringBuilder 效率会好一点
val str4 = new StringBuilder()
str4.append(name)
str4.append(",")
str4.append(age)
str4.append(",")
str4.append(clazz)
println(str4)
// scala中的方式
val str5 = s"${name},${age},${clazz}"
println(str5)
// 类型转换
// 只要保证数据是符合规范的 就可以直接to类型直接转换
val str2: String = "123456"
val int1: Int = str2.toInt
val int2: Long = str2.toLong
// Any:是所有类型的基类 相当于Java中的Object
// Any下面有两个子类分别是:AnyRef、AnyVal
val anyRef: AnyRef = "abc" // AnyRef 表示所有引用类型的基类
val anyVal: AnyVal = 1 // AnyVal 表示所有值类型的基类
// 算术运算符 + - * / %
println(2 * 3)
println("#" * 20) // 表示输出20个# 这里的 * 不是算数运算符
// 关系运算符 > < == >= <= !=
// 位运算符 ~按位取反 &按位与 |按位或 ^异或
// 循环
// for while
// for 没有Java中的 for(int i = 0;i<10;i++){}
// for 同Java中的for each类似 主要用于遍历数据容器
// 循环主要用while
// 计算1~100的和
var i = 1
var sum = 0
while (i <= 100) {
sum += i
i += 1 // scala中没有++ --
}
println(sum)
println("#" * 20)
// do while
do {
println("do while 循环体至少会执行一次")
} while (100 > 200)
println("#" * 20)
// 定义了一个List
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
for (elem: Int <- list) { // 相当于Java的for each 写法不一样而已
println(elem)
}
// 计算1~100的和
var sum2 = 0
for (i <- 1 to 100) { // i 相当于 1~100
sum2 += i
}
println(sum2)
var sum3 = 0
for (i <- 1 until 100) { // i 相当于 1~100
sum3 += i
}
println(sum3)
println("#" * 20)
// Range函数(起始位置,结束位置,步长)
// 按照步长生成一个包含起始位置不包含结束位置的序列
for (i <- Range(1, 10, 2)) {
print(i + " ")
}
println()
println("#" * 20)
// 输出1~10的奇数
for (i <- 1 to 10 if i % 2 == 1) {
println(i)
}
// if -else if- else 选择结构 同Java一致
val nianLing = 20
if (nianLing >= 18) {
println("成年")
} else if (nianLing >= 0 && nianLing < 18) {
// && 与
// || 或
// ! 非
println("未成年")
} else {
println("年龄不能为负数")
}
}
}
五、读写文件、JDBC读取Mysql
import java.io.{BufferedReader, FileReader, FileWriter, PrintWriter}
import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}
import scala.io.{BufferedSource, Source}
object Demo7FileIOAndJDBC {
def main(args: Array[String]): Unit = {
// Java中的文件读写
val br = new BufferedReader(new FileReader("data/students.txt"))
var line = br.readLine()
while (line != null) {
println(line)
line = br.readLine()
}
br.close()
println("#" * 100)
// Scala中的文件读写
val source: BufferedSource = Source.fromFile("data/students.txt")
val sIt: Iterator[String] = source.getLines()
for (line <- sIt) {
println(line)
}
println("#" * 100)
// 简写
// 链式调用
Source.fromFile("data/students.txt")
.getLines()
.foreach(println)
// 写文件
// PrintWriter FileWriter
val writer = new PrintWriter("data/output1.txt")
writer.println("helloWorld") // 会加上换行符
writer.write("helloWorld") // 不会换行
writer.close()
val writer1 = new FileWriter("data/output2.txt")
writer1.write("ok\n")
writer1.write("ok\n")
writer1.write("ok\n")
writer1.close()
// JDBC
// scala中没有正对JDBC做特定的优化
// 实际上用的是Java那一套流程
Class.forName("com.mysql.jdbc.Driver")
val conn: Connection = DriverManager.getConnection("jdbc:mysql://rm-bp1h7v927zia3t8iwho.mysql.rds.aliyuncs.com:3306/students", "masu001", "123456")
val stat: PreparedStatement = conn.prepareStatement("select * from students where age = ?")
stat.setInt(1, 23)
val set: ResultSet = stat.executeQuery()
while (set.next()) {
val name: String = set.getString("name")
val age: Int = set.getInt("age")
val clazz: String = set.getString("clazz")
println(s"${name},${age},${clazz}")
}
}
}
六、封装继承多态
// 类中可以定义 变量、方法、构造函数
class Stu(id: String, name: String, age: Int) {
println("这是默认的构造函数")
// 定义即赋值
val _id = id
val _name = name
val _age = age
var _clazz: String = _ // _表示待会再赋值 相当于占位符
// 重写构造方法 那么就需要重新实现this方法
def this(id: String, name: String, age: Int, clazz: String) = {
// 在这个this方法第一行代码 必须是调用默认的构造方法
this(id, name, age)
println("重写构造方法")
_clazz = clazz
}
// 重写父类的方法
override def toString(): String = {
// return 可以省略 默认会将最后一行作为返回值
s"Stu(${_id}, ${_name}, ${_age},${_clazz})"
}
def hello(): Unit = {
println("hello")
}
}
object Demo8ScalaClass {
def main(args: Array[String]): Unit = {
// 创建对象
val stu1 = new Stu("0001", "张三", 19)
println(stu1)
println(stu1._name)
stu1.hello()
val stu2 = new Stu("0002", "李四", 19, "文科一班")
println(stu2)
println(stu2._name)
stu2.hello()
}
}
object Demo9ScalaExtends {
def main(args: Array[String]): Unit = {
val a = new A("0001", "张三")
val b = new B("0001", "张三", 19)
val c = new C("0001", "张三", "文科一班")
// 多态:父类引用指向子类对象
runTwice(a)
runTwice(b)
runTwice(c)
val str: String = "abc"
val str1: Object = "abc" // 多态
}
def runTwice(any: A): Unit = {
any.run()
any.run()
}
}
// 父类
class A(id: String, name: String) {
val _id = id
val _name = name
println("这是A的构造方法")
def run(): Unit = {
println("A can run")
}
}
// 继承的时候使用extends关键字
// 同Java一样只能继承一个父类
// 在extends时就需要调用父类的构造方法
class B(id: String, name: String, age: Int) extends A(id, name) {
println("这是B的构造方法")
override def run(): Unit = {
println("B can run")
}
}
class C(id: String, name: String, clazz: String) extends A(id, name) {
println("这是C的构造方法")
override def run(): Unit = {
println("C can run")
}
}
七、Scala Apply
object Demo11ScalaApply {
def main(args: Array[String]): Unit = {
val stu = new StuA("001", "张三")
val stuB = new StuB("002", "李四")
val stuB2 = StuB("003", "王五") // 相当于会去调用StuB的伴生对象中的apply方法
}
}
class StuA(id: String, name: String) {
val _id = id
val _name = name
}
class StuB(id: String, name: String) {
val _id = id
val _name = name
}
// class StuB的伴生对象
object StuB {
def apply(id: String, name: String) = new StuB(id, name)
}
八、函数
object Demo12ScalaFunc1 {
// 函数可以定义在类class中、object中、函数中
/**
* def 声明函数的关键字
* main 方法名
* args: Array[String] 参数名: 参数类型
* Unit 表示函数的返回值 相当于void
* {方法体}
*/
def main(args: Array[String]): Unit = {
println("hello World")
// 函数的调用: 函数名(参数1,参数2)
func1("hello", "world")
println(func2("张三2"))
println(func3("张三3"))
println(func4("张三4"))
println(func5("张三5"))
println(func6)
}
// 定义在object中的函数可以直接调用
def func1(param1: String, param2: String): Unit = {
println(s"${param1},${param2}")
}
// 函数的省略
/**
* 1、return关键字可以省略 默认以最后一行代码最为返回值
* 2、如果函数只有一行代码,花括号可以省略
* 3、返回值类型可以省略
* 4、如果函数没有参数 括号可以省略
*/
def func2(name: String): String = {
return "hello:" + name
}
def func3(name: String): String = {
"hello:" + name
}
def func4(name: String): String = "hello:" + name
def func5(name: String) = "hello:" + name
def func6 = "hello World" // func6是一个函数 不是变量!
}
object Demo13ScalaFunc2 {
/**
* 面向对象编程:将对象传来传去 对象是有类型限制的
* 面向函数编程:将函数传来传去 函数也应该有类型限制
* 函数的类型是什么???
* 函数的类型由函数的 参数类型(个数、顺序、类型都要一致) 以及 返回值类型 共同决定
* 函数式编程(面向函数编程、高阶函数):
* 1、以函数作为参数
* 2、以函数作为返回值
*
*/
def main(args: Array[String]): Unit = {
func1()
// 在main方法中定义函数
def func1(): Unit = {
println("hello" + func2())
def func2() = {
"world"
}
}
// funX支持传入一个函数
// 该函数的类型有限制,必须由两个参数都是String类型,而且返回值类型为Int
funX(f1)
funX(f2)
// funX(fun1) // fun1的类型不符合要求
/**
* 匿名函数的简化:
* 1、如果方法体只有一行 {}可以省略
* 2、返回值类型不能指定 会自动推断
* 3、参数类型可以省略
* 4、如果参数只有一个 括号可以省略
* 5、如果参数只被使用一次 参数可以省略 用 _ 替代
*/
funX((str1: String, str2: String) => {
// 方法体
str1.toInt + str2.toInt + 3
})
// 如果方法体只有一行 {}可以省略
funX((str1: String, str2: String) => str1.toInt + str2.toInt + 3)
// 参数类型可以省略
funX((str1, str2) => str1.toInt + str2.toInt + 3)
// funX2支持传入一个函数
// 该函数的类型有限制,参数是String类型,返回值类型为Int
// 如果参数只有一个 括号可以省略
funX2(str1 => str1.toInt + 4)
// 如果参数只被使用一次 参数可以省略 用 _ 替代
funX2(_.toInt + 4)
println(f("20", "30"))
funX(f)
}
// 参数为 String类型 返回值类型为Int 的 函数
def fun1(str: String) = {
str.toInt + 100
}
// 参数为 String类型 返回值类型为Int 的 函数
def fun2(str: String) = {
str.toInt + 200
}
// 参数为 String类型 返回值类型为String 的 函数
// fun1 与 fun2 是同一类型的函数 fun3不属于同一类型
def fun3(str: String) = {
str + 100
}
// 1、以函数作为参数
// funX 支持传入一个函数f(类型:参数为String,String 返回值为Int) 并进行调用
def funX(f: (String, String) => Int) = {
println("开始调用f")
val i: Int = f("100", "200")
println(i)
println("结束调用")
}
def f1(str1: String, str2: String): Int = {
str1.toInt + str2.toInt + 1
}
def f2(str1: String, str2: String): Int = {
str1.toInt + str2.toInt + 2
}
// funX2 支持传入一个函数f(类型:参数为String 返回值为Int) 并进行调用
def funX2(f: String => Int) = {
val i = f("100")
println(i)
}
/**
* 匿名函数:实际上是对函数的简写
* 按照字面理解就是没有名字的函数
* (str1: String, str2: String) => {
* // 方法体
* str1.toInt + str2.toInt + 3
* }
* (str1: String, str2: String) 表示匿名函数的参数及类型
* =>
* {方法体} 方法体中的最后一行代码作为匿名函数的返回值
*
* 匿名函数 实际上为了方便调用 可以拥有名字
*
*/
val f = (str1: String, str2: String) => {
// 方法体
str1.toInt + str2.toInt + 3
}
}
object Demo14ScalaFunc3 {
def main(args: Array[String]): Unit = {
// 函数作为参数的运用
val array: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
// 对array中的每一个元素进行 +1
var index = 0
while (index < array.length) {
val originalValue: Int = array(index) // 取出原有的值
val newValue: Int = originalValue + 1 // +1
array(index) = newValue // 将新的值重新赋给array(index)
index += 1
}
// 按照指定的分隔符 将 array中的所有元素进行拼接并输出
println(array.mkString(","))
// 对array中的每一个元素进行 +2
var index1 = 0
while (index1 < array.length) {
array(index1) += 2
index1 += 1
}
// 按照指定的分隔符 将 array中的所有元素进行拼接并输出
println(array.mkString(","))
// Java的思想:用while循环做
// Scala 的思想:用函数式编程来做
// map方法可以传入一个函数f,会将f作用在array中的每一个元素上,最后会返回一个新的array
val newArray: Array[Int] = array.map(add1)
println(newArray.mkString(","))
val newArray1: Array[Int] = array.map(add2)
println(newArray1.mkString(","))
// 使用匿名函数
val newArray2: Array[Int] = array.map(_ + 1)
println(newArray2.mkString(","))
val newArray3: Array[Int] = array.map(_ + 2)
println(newArray3.mkString(","))
}
def add1(i: Int): Int = {
i + 1
}
def add2(i: Int): Int = {
i + 2
}
}
object Demo15ScalaFunc4 {
/**
* 2、以函数作为返回值
*
*/
def main(args: Array[String]): Unit = {
// "100" "200"
val f2: String => Int = func1("100") // 返回了一个函数
val i: Int = f2("200")
println(i)
println(func3(2, 3))
println(func3(3, 3))
println(func3(4, 3))
println(func3(5, 3))
// 偏函数:将有X个参数的函数 变成X-N个参数的函数 N表示传入的固定参数
println(func3(2))
val f4: Int => Double = func4(3)
println(f4(2))
println(f4(3))
println(f4(4))
println(f4(5))
val f5: Int => Double = func5(3)
println(f5(2))
println(f5(3))
println(f5(4))
println(f5(5))
// 直接调用
println(func4(2)(3))
println(func4(3)(3))
println(func4(4)(3))
println(func5(2)(3))
println(func5(3)(3))
println(func5(4)(3))
}
// 如果以函数最为返回值 需要手动给定返回值类型
def func1(str1: String): String => Int = {
def func2(str2: String) = {
str1.toInt + str2.toInt
}
func2
}
// 计算 a的b次方
def func3(a: Int, b: Int = 3) = {
Math.pow(a, b)
}
def func4(b: Int): Int => Double = {
def func4_1(a: Int) = {
Math.pow(a, b)
}
func4_1
}
// func4 省略的写法
// 函数柯里化:将一个有N个参数的函数 变成 N个只有一个参数的函数
def func5(b: Int)(a: Int): Double = {
Math.pow(a, b)
}
}
八、集合
List
import scala.collection.mutable.ListBuffer
object Demo16ScalaList {
/**
* List 列表
* 不可变的,有序的,里面的元素可以不唯一,类型必须唯一(除非将泛型指定为Any)
*/
def main(args: Array[String]): Unit = {
// 定义
val list: List[Int] = List(1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4)
println(list(2)) // 通过下标取元素
// 常见的方法
println(list.max) // 最大值
println(list.min) // 最小值
println(list.sum) // 求和
println(list.length) // 长度
println(list.head) // 取第一个元素
println(list.tail) // 取除一个元素以外的所有元素
println(list.reverse) // 反转
println(list.distinct) // 去重
println(list.isEmpty) // 判断是否为空
println(list.take(5)) // 取前5个元素
println(list.mkString(",")) // 按照指定的分隔符 将list中所有的元素与分隔符拼接并构建成字符串
// map方法需要传入一个函数f,f的类型为: “参数类型与list的元素类型一致 返回值类型自定 "
// 会将函数f 作用在list中的每一个元素上
// 最后会返回一个新的list
val list2 = list.map(_ * 2)
println(list)
println(list2)
val list3: List[String] = List("hello,world,hello", "java,scala,c++", "hadoop,hbase,hive")
for (elem <- list3.map(_.split(","))) {
println(elem.toList)
}
// flatMap方法 不仅可以将传入的函数f 作用每个元素上
// 还会对函数f返回的结果进行扁平化处理(展开)
// 限制条件:传入的函数f的返回值类型 必须是集合类型
// 最后会将展开后的结果以List的形式返回
val list5: List[String] = list3.flatMap(_.split(","))
println(list5)
// 把list中的奇数过滤出来
// filter方法需要传入一个函数f,函数f的返回值类型必须是Boolean类型
// 会根据返回的是true则保留 返回false则舍弃
println(list)
val list6 = list.filter((i: Int) => {
var flag = false
if (i % 2 == 1) {
flag = true
}
flag
})
println(list.filter(_ % 2 == 1)) // 简写方式
println(list6)
// foreach 需要一个输入类型同List中元素类型一致,返回值类型为Unit 这样的函数
// println 输入类型为Any 返回值类型为Unit
// Any是Int的父类 所以println可以直接作为foreach的函数传入
// 同map的区别就是 一个有返回值 一个没有没有返回值
list.foreach(println)
// 直接排序
val sorted: List[Int] = list.sorted
println(sorted)
val l1 = List(1, 2)
val l2 = List(3, 3)
val l3 = List(2, 1)
val l123 = List(l1, l2, l3) // 二维List
// 指定按照什么进行排序
val ll = l123.sortBy(list => {
list(1)
})
println(ll)
// 指定排序的规则
val ll2 = list.sortWith((x: Int, y: Int) => {
x < y
})
println(ll2)
println("#" * 20)
/**
* 可变的List -> ListBuffer
* 同List最大的区别就在于可以增加删除修改元素
*/
val listB: ListBuffer[Int] = ListBuffer(1, 1, 2, 3, 3, 4, 5, 6, 9, 8, 7)
// append 增加一个元素 参数为: elem:Int*
// Int* 表示可变参数(可以接收任意多个Int类型的参数)
// 将元素添加到末尾
listB.append(1, 2, 3, 4)
println(listB)
listB.+=(5)
listB.+=(6, 7, 8)
listB += 9
println(listB)
// 删除元素
// 从头开始删除
listB.-=(4) // 按照元素从左往右匹配 将第一个匹配的值删除
println(listB)
listB.remove(9) // 按照索引删除
println(listB)
listB -= 9
println(listB)
// 修改元素
listB(4) = 4
println(listB)
listB.update(0, -1)
println(listB)
// 插入元素
listB.insert(1, 0, 0, 0, 0)
println(listB)
listB.insertAll(5, List(0, 1))
println(listB)
}
}
SET
import scala.collection.mutable
import scala.collection.mutable.HashSet
object Demo17ScalaSet {
/**
* Set 集合
* 无序、元素不能重复(会自动去重)、不可变
*
*/
def main(args: Array[String]): Unit = {
val set: Set[Int] = Set(1, 1, 2, 2, 2, 3, 4, 4, 5, 6, 7, 9, 8)
println(set(9)) // 判断元素是否在集合中
println(set)
println(set.max)
println(set.min)
println(set.size)
println(set.head)
println(set.tail)
println(set.take(3))
// 。。。。。
val set1: Set[Int] = set.map(_ + 1)
println(set1)
// Set可以理解为数学中的集合
// 交集 并集 差集
val s1 = Set(1, 2, 3, 4, 5)
val s2 = Set(3, 4, 5, 6, 7)
println(s1 & s2) // 交集
println(s1 | s2) // 并集
println(s1 &~ s2) // 差集
/**
* 可变Set -> HashSet
*/
val hSet: mutable.HashSet[Int] = HashSet(1, 2, 2, 3, 4, 5, 6, 6)
println(hSet)
hSet.add(5)
hSet.add(7)
println(hSet)
hSet.remove(2)
hSet.+=(8)
hSet.-=(5)
println(hSet)
hSet.foreach(println)
// 过滤 会返回一个新的HashSet
val hSet2: mutable.HashSet[Int] = hSet.filter(_ % 2 == 0)
println(hSet2)
}
}
Map
import scala.collection.mutable
object Demo18ScalaMap {
/**
* Map : kv格式的数据
* 无序、key值不能重复、不可变
* 可以根据key获取value 所以非常适合查询的场景
*
*/
def main(args: Array[String]): Unit = {
val map = Map(("k1", "v1"), ("k2", "v2"), "k3" -> "v3")
map.foreach(t2 => {
val key: String = t2._1
val value: String = t2._2
println(key + "," + value)
})
// 根据key判断存不存在
println(map.contains("k1"))
println(map.contains("k4"))
// 通过key获取value
println(map.get("k1")) // Some(v1)
println(map.get("k1").get) // v1
println(map.get("k4")) // None
println(map.getOrElse("k5", "默认值")) // key如果不存在 就返回指定的默认值
/**
* 可变Map
*/
val hMap: mutable.HashMap[String, String] = mutable.HashMap("k1" -> "v1", "k2" -> "v2", "k3" -> "v3")
hMap.+=("k4" -> "v4")
println(hMap)
}
}
Tuple
object Demo19ScalaTuple {
/**
* Tuple 元组 同List很相似
* 元组是不可以改变的 最大长度为22
* 没有可变元组与不可变元组一说
* 虽然不可以用索引取值 但它是有序的
*/
def main(args: Array[String]): Unit = {
val tuple3: (Int, Int, Int) = Tuple3(1, 2, 3) // 三元组
println(tuple3)
println(tuple3._1) // 第一个元素
println(tuple3._2) // 第二个元素
println(tuple3._3) // 第三个元素
val tuple2: (Int, Int) = (1, 2) // 动态推断元组的类型
println(tuple2)
// 只有一个元素的元组
// Python的方式在创建时加一个 逗号 这种方式在Scala中通不过编译 那就使用Tuple1(1)创建
val i: Tuple1[Int] = Tuple1(1)
println(i._1)
}
}
九、模式匹配match
object Demo20ScalaMatch {
/**
* 模式匹配 match
* java中的模式匹配可以匹配 基本数据类型的值、字符串、枚举
* scala中的模式匹配可以匹配 基本数据类型的值、字符串、枚举、对象、类型
*/
def main(args: Array[String]): Unit = {
// 1、匹配基本数据类型的值
val i: Int = 3
i match {
case 1 => println("i的值为" + 1)
case 2 => println("i的值为" + 2)
case 3 => println("i的值为" + 3)
case _ => println("其他情况")
}
// 2、匹配字符串
val str: String = "abcde"
str match {
case "abcd" => println("abcd")
case "abcde" => println("abcde")
case "abcdf" => println("abcdf")
case "abcdg" => println("abcdg")
case _ => println("其他情况")
}
// 4、匹配对象(样例类的对象)
val zhangSan: StuC = StuC("001", "zhangSan")
zhangSan match {
case StuC("001", "zhangSan") => println("zhangSan")
case StuC("002", "zhangSan") => println("zhangSan2")
case StuC("003", "xiaoming") => println("xiaoming")
case _ => println("其他情况")
}
// 5、匹配类型
// Any相当于Object
val str2: Any = "string"
str2 match {
case i: Int => println(i)
case f: Float => println(f)
case s: String => println(s)
case _ => println("其他情况")
}
// scala中的match可以有返回值
val smatch: Any = str2 match {
case i: Int => i
case f: Float => f
case s: String => s
case _ => "其他情况"
}
println(smatch)
// match在Map中的运用
val map = Map("k1" -> "v1", "k2" -> "v2", "k3" -> "v3")
// Option 表示有的时候去调用函数去获取值
// 有时候有返回值 有的时候没有 为了避免直接返回null发生空指针异常
// 在Scala中就用Option的方式去应对
// Option下面就两个选项(两个子类) 一个是 Some 另一个是None
val v: Option[String] = map.get("k1")
val res = v match {
case None => "默认值"
case Some(s) => s
}
println(res)
// 相当于getOrElse
val res2: String = map.getOrElse("k1", "默认值")
println(res2)
}
case class StuC(id: String, name: String)
}
十、隐式转换
隐式转换:动态的给对象增加方法
- 1、隐式转换方法
- 2、隐式转换变量
- 3、隐式转换类
概念:以implicit关键字声明的,带有单个参数的函数,这种函数将会自动应用,将值从一种类型转化为另一种类型.
1、隐式转换方法
object Demo21ScalaImplicit1 {
/**
* 隐式转换:动态的给对象增加方法
*
* 1、隐式转换方法
* 2、隐式转换变量
* 3、隐式转换类
*
*/
def main(args: Array[String]): Unit = {
// 1、隐式转换方法
// 相同作用域范围内只能存在一个”同类型“(输入的参数类型与返回值类型一致)的隐式转换函数
def func1(i: Int) = {
println(i + 100)
}
val s10: String = "10"
func1(10)
// func1(s10) // 参数类型不匹配 会报错
func1(Integer.parseInt(s10)) // 显示转换
implicit def stringToInt(str: String): Int = {
Integer.parseInt(s10)
}
val i: Int = stringToInt(s10)
println(i)
func1(stringToInt(s10))
// func1 需要Int类型的参数 s10是String类型的 如果没有隐式转换方法 直接传入会报错
// Scala在编译的时候会自动去寻找 隐式转换方法 找一个 String => Int 的隐式转换方法 并自动进行调用
func1(s10)
}
}
2、隐式转换变量
object Demo22ScalaImplicit2 {
def main(args: Array[String]): Unit = {
// 2、隐式转换变量
// 同一个作用域范围内的同类型的隐式转换变量只能有一个
def addPrefix(str: String)(implicit prefix: String) = {
println(str + "," + prefix)
}
implicit val pre: String = "默认后缀"
addPrefix("spark")("火花")
// addPrefix 本来需要调用两次 这里只调用了一次
// 会自动的去寻找当前作用域范围内的 同implicit关键字修饰的方法中的参数的类型一致的 隐式转换变量
addPrefix("java")
}
}
3、隐式转换类
import scala.io.Source
object Demo23ScalaImplicit3 {
def main(args: Array[String]): Unit = {
// 3、隐式转换类
// 动态的给 同类中构造方法需要的参数类型 一样的变量 加上该类中的方法
// 读取students.txt
// Source.fromFile("data/students.txt")
// .getLines()
// .foreach(println)
// 读取score.txt
// Source.fromFile("data/score.txt")
// .getLines()
// .foreach(println)
// 使用ReadFile类
// new ReadFile("data/students.txt").read().foreach(println)
// new ReadFile("data/score.txt").read().foreach(println)
// 在class前加上implicit关键字
// 直接使用字符串就可以调用 ReadFile类中的方法了
// 相当于给 字符串类型加上了 ReadFile类中的方法
"data/students.txt".read().foreach(println)
"data/score.txt".read().foreach(println)
}
// 定义了一个类 支持传入一个路径path 有一个方法read()可以调用 会根据path读取文件并返回一个迭代器
implicit class ReadFile(path: String) {
def read() = {
val itr: Iterator[String] = Source.fromFile(path)
.getLines()
itr
}
}
}
十一、链式调用
例子:wordcount
object Demo25ScalaWordCount {
Source.fromFile("data/words.txt")
.getLines()
.toList // 转List
.flatMap(_.split(",")) // 切分每条数据并展开
.groupBy(word => word) // 按每个word分组
.map(kv => (kv._1, kv._2.size)) // 统计单词次数
.foreach(println) // 打印
}
scala容器和方法
Scala的Option[T]是容器对于给定的类型的零个或一个元件。Option[T]可以是一个
例如,Scala映射get方法产生,如果给定的键没有在映射定义的一些(值),如果对应于给定键的值已经找到,或None
Map的Get方法返回的就是一个Option
val map = Map("k1" -> "v1", "k2" -> "v2", "k3" -> "v3")
// Option 表示有的时候去调用函数去获取值
// 有时候有返回值 有的时候没有 为了避免直接返回null发生空指针异常
// 在Scala中就用Option的方式去应对
// Option下面就两个选项(两个子类) 一个是 Some 另一个是None
val v: Option[String] = map.get("k1")
val res = v match {
case None => "默认值"
case Some(s) => s
}
println(res)
scala练习
1、统计班级人数
2、统计学生的总分
//1、统计班级人数
import scala.io.Source
object Test01Scala {
def main(args: Array[String]): Unit = {
Source.fromFile("data/students.txt")
.getLines()
.map(line=>{
val strings = line.split(",")
val clazz = strings(4)
(clazz,1)
})
.toList
.groupBy(_._1)
.map(kv=>(kv._1,kv._2.size)).foreach(println)
}
}
//2、统计学生的总分
object Test02Scala {
def main(args: Array[String]): Unit = {
val hMap: mutable.HashMap[String,Int] = mutable.HashMap()
val stringToTuples = Source.fromFile("data/score.txt")
.getLines()
.toList
.foreach(line=>{
val id = line.split(",")(0)
val score = line.split(",")(2).toInt
if (hMap.contains(id)){
val sumscore = hMap.get(id).get+score
hMap.update(id,sumscore)
}else{
hMap.put(id,score)
}
hMap
}
)
hMap.foreach(println)
}
}