Scala基础

Posted hsiehchou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala基础相关的知识,希望对你有一定的参考价值。

1、scala编程语言
2、Spark Core : Spark内核 ,最重要的一个部分
3、Spark SQL : 类似于 hive 和 pig。数据分析引擎。sql语句提交到spark集群中运行
4、Spark Streaming :类似于 storm,用于流式计算、实时计算。本质:一个离线计算

一、Scala基础

1、scala简介

1)scala是一个多范式的编程语言(支持多种方式的编程)
(1)使用面向对象编程:封装、继承、多态
(2)使用函数式编程:最大的特定
优点:代码非常简洁
缺点:可读性太差,尤其是隐式类、隐式函数、隐式参数

2)安装和配置scala
(1)基于JDK,先安装JDK
(2)scala:2.11.8(spark 2.1.0)
(3)配置环境变量:SCALA_HOME
(4)%SCALA_HOME%\bin 配置到path中
下载地址:https://www.scala-lang.org
文档地址:https://www.scala-lang.org/api/2.11.8/#scala.math.package

3)开发环境
REPL命令行
IDEA : 需要安装scala插件

2、Scala中的数据类型和变量常量

1、注意一点:scala中所有的数据,都是对象
举例:1 java int 。在scala中,1 就是一个对象

2、基本数据类型
Byte :8位有符号数字
Short :16位有符号数字
Int :32位有符号数字
Long : 64位有符号数字
Float :32位有符号数字
Double :64位有符号数字
Char :8位有符号数字
Boolean : 1位有符号数字

字符串类型
String
字符
Char :8位有符号数字

scala中字符串的插值操作:就是相当于字符串的拼接

scala> var s1 : String = "Hello "
s1: String = "Hello "
scala> "My name is Tom and ${s1}"
res1: String = My name is Tom and ${s1}

插值操作时,需要加入 s

scala> s"My name is Tom and ${s1}"
res2: String = "My name is Tom and Hello "

3、变量var和常量val

scala> val s2 :String = "Hello all"
s2: String = Hello all
scala> s2 = "Hello everyone"
<console>:12: error: reassignment to val
s2 = "Hello everyone"

4、Unit类型和Nothing类型
(1)Unit类型,就是java中的void,没有返回值

scala> val f = ()
f: Unit = ()

返回值 Unit类型
() 代表了一个函数,这个函数没有返回值

(2)Nothing类型,在执行过程中,产生了异常Exception
举例:
scala函数:scala中函数非常重要,是scala的头等公民
用法很多:函数式编程、高阶函数

def myFunction = 函数的实现

scala> def myFun = throw new Exception("Some Error")
myFun: Nothing

3、函数(头等公民)

(1)scala内置函数,可以直接使用的函数

scala> max(1,2)
<console>:12: error: not found: value max
max(1,2)
^
scala> import scala.math
final package math
scala> import scala.math._
import scala.math._

_ 就相当于java中的 * 代表包内所有东西

scala> max(1,2)
res4: Int = 2

res4: Int = 2
定义了一个变量 res4 ,接收了 max 函数的返回值。scala中支持类型的推导。
res4 = “”

(2) 自定义函数
语法:
def 函数名称([参数名称:参数类型]*) : 返回值类型 = {
函数的实现
}

举例:
1)求和

scala> def sum(x:Int,y:Int):Int = x + y
sum: (x: Int, y: Int)Int
scala> sum(1,2)
res5: Int = 3

2)求阶乘,5!= 5 * 4* 3 2 1
递归

scala> def myFactor(x:Int):Int = {
| if(x<=1)
| 1
| else
| x*myFactor(x-1)
| }
myFactor: (x: Int)Int
scala> myFactor(5)
res6: Int = 120

注意:没有return语句
函数的最后一句话,就是函数的返回值

3)求输入的年份是否是闰年
闰年:
普通闰年:可以被4整除但是不能被100整除的年份
世纪闰年:可以被400整除的年份

scala> def isLeapYear(x:Int) = {
| if(( x%4 == 0 && x%100 != 0) || (x%400==0)) true
| else false
| }
isLeapYear: (x: Int)Boolean
scala> isLeapYear(2019)
res7: Boolean = false
scala> isLeapYear(2008)
res8: Boolean = true

注意:
1、( x%4 == 0 && x%100 != 0) || (x%400==0)
2、函数定义的时候,可以不写返回值,因为scala支持类型推导

4、循环语句

1、类似于java的用法 while dowhile for

/**
* for循环
*
* 定义一个集合
*/
var list = List("dfg","Agddg","Fd")
println("------------for循环中的第一种写法-------------")
for( s <- list ) println(s)
println("------------for循环中的第二种写法-------------")
//打印长度大于3的名字
for{
s <- list
if(s.length > 3)
}println(s)
println("------------for循环中的第三种写法-------------")
//对第二种进一步简化
for( s<- list if s.length <= 3) println(s)
println("------------for循环中的第四种写法-------------")
/**
* 1、把list中所有元素都变成大写
* s <- list
* s1 = s.toUpperCase
*
* 2、返回一个新的集合
* yield(s1)
*
*/
var newList = for {
s <- list
s1 = s.toUpperCase
}yield(s1)
for(s <- newList) println(s)
println("------------while循环-------------")
//定义循环变量
var i = 0
while( i < list.length){
println(list(i))
/**
* 自增
*
* 注意scala中没有i++
*/
i += 1
}
println("------------do while循环-------------")
//定义循环变量
var j = 0
do{
println(list(j))
j += 1
}while( j < list.length)

2、foreach循环(Spark算子)

println("------------foreach循环-------------")
/**
* foreach scala里面有 spark里面
* map
*
* 没有返回值,map有返回值
* foreachlist的一个方法
*/
list.foreach(println)
/**
* foreach 说明
* list.foreach(println)
*
* 我们把一个函数传入了foreach
* 高阶函数(函数式编程)
*/
/**
* 判断101-200之间有多少个素数
*
* 判断素数的方法:
* x%2 -----x%sqrt(根号)x
* 当都不能被整除的时候就是素数
*
*
* 16
* sqrt(16) = 4
* 2 3 4
*
* 16%2 == 0 ?
* 16%3 == 0 ?
* 16%4 == 0 ?
*
* 编程思路:
* 两层循环:
* 第一层:101-200
* 第二层:2--sqrt第一层
*
*/
println("---------循环嵌套-------------")
var count : Int = 0 //保存结果
var index_outer = 0
var index_inner = 0
for(index_outer <- 101 until 200){
index_inner = 2
var b = false //标识是否能被整除
breakable{
while(index_inner <= sqrt(index_outer)){
if(index_outer % index_inner ==0) {
b = true
break
}
index_inner += 1
}
}
if(!b) count += 1
}
println("个数为:" + count)
/**
* 算法分析:
* 1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
* 2、对每一对相邻元素都做上述工作,循环完第一次后,最后的元素,就是最大的元素。
* 3、针对剩下的元素,重复上面工作(除了最后一个元素)
*
* 程序分析:
* 1、两层循环
* 2、外层循环控制比较的次数
* 3、内层循环控制到达的位置,就是 结束比较 的位置
**/
println("---------冒泡排序-------------")
var a = Array(12,3,6,3,6,7,3,8,34,3)
println("---------排序前---------------")
a.foreach(println)
for(i <- 0 until a.length - 1){
for(j <- 0 until a.length - i - 1){
if(a(j) > a(j+1)){
//交换
var tmp = a(j)
a(j) = a(j+1)
a(j+1) = tmp
}
}
}
println("---------排序后---------------")
a.foreach(println)

5、scala的函数参数

1、函数参数的求值策略
(1)call by value :
对函数的实参求值,并且只求一次

(2)call by name : =>
函数实参在函数体内部用到的时候,才会被求值

举例:

scala> def test1(x:Int,y:Int) = x + x
test1: (x: Int, y: Int)Int
scala> test1(3+4,8)
res9: Int = 14
scala> def test2(x : => Int,y : => Int) = x+x
test2: (x: => Int, y: => Int)Int
scala> test2(3+4,8)
res10: Int = 14

执行过程对比:
test1 —> test1(3+4,8) —> test1(7,8) —> 7+7 —> 14
test2 —> test2(3+4,8) —> (3+4) + (3+4) —> 14

(3)复杂的例子
def bar(x:Int,y : => Int) : Int = 1
x 是 value y 是 name

定义一个死循环:
def loop() : Int = loop

调用bar函数的时候:
1、bar(1,loop)
2、bar(loop,1)–>产生死循环

哪个方式会产生死循环?

scala> def bar(x:Int,y : => Int) : Int = 1
bar: (x: Int, y: => Int)Int
scala> def loop() : Int = loop
loop: ()Int
scala> bar(1,loop)
res11: Int = 1
scala> bar(loop,1)

解析:
1、虽然 y 是 name, 每次调用的时候会被求值。但是,函数体内,没有调用到y.
2、x 是 value,对函数参数求值,并且只求一次。虽然后面没有用到x,但求值时产生了死循环

2、scala中函数参数的类型
(1)默认参数
当你没有给参数值赋值的时候,就会使用默认值

def fun1(name:String="Ti") :String = "Hello " + name
scala> def fun1(name:String="Ti") :String = "Hello " + name
fun1: (name: String)String
scala> fun1("An")
res0: String = Hello An
scala> fun1()
res1: String = Hello Ti

(2)代名参数
当有多个默认参数的时候,通过代名参数可以确定给哪个函数参数赋值。

def fun2(str:String = "Hello " , name:String = " Ti " ,age:Int = 20) = str + name + " age is " +age
scala> def fun2(str:String = "Hello " , name:String = " Ti " ,age:Int = 20) = str + name + " age is " +age
fun2: (str: String, name: String, age: Int)String
scala> fun2()
res2: String = Hello Ti age is 20
scala> fun2("An")
res3: String = An Ti age is 20
scala> fun2(name="An")
res4: String = Hello An age is 20

(3)可变参数
类似于java中的可变参数,即 参数数量不固定

scala> def sum(args:Int*)= {
| var result = 0
| for(s<-args) result +=s
| result
| }
sum: (args: Int*)Int
scala> sum(1,2,3,4)
res5: Int = 10
scala> sum(1,2,3,4,3,4)
res6: Int = 17

6、懒值(lazy)

铺垫:Spark的核心是 RDD(数据集合),操作数据集合的数据,使用算子来操作RDD(函数、方法)

算子:
Transformation : 延时加载,不会触发计算
Action : 会立刻触发计算

定义:常量如果是lazy的,他的初始化会被延迟,推迟到第一次使用该常量的时候
举例:
scala> var x : Int = 10
x: Int = 10

scala> val y : Int = x+1
y: Int = 11

y 的值是x+1 定义后会立即进行计算

scala> lazy val z : Int = x+1
z: Int = <lazy>

z的初始化会被延迟

scala> z
res0: Int = 11

当我们第一次使用z的时候,才会触发计算

读文件:
scala> val words = scala.io.Source.fromFile(“E:\student.txt”).mkString
words: String =
1 Tom 12
2 Mary 13
3 Lily 15

scala> lazy val words = scala.io.Source.fromFile("E:\\student.txt").mkString
words: String = <lazy>

scala> words
res1: String =
1 Tom 12
2 Mary 13
3 Lily 15

scala> lazy val words = scala.io.Source.fromFile("E:\\student121.txt").mkString
words: String = <lazy>

定义成lazy后,初始化被延迟,所以不会抛异常
scala> val words = scala.io.Source.fromFile(“E:\student121.txt”).mkString
java.io.FileNotFoundException: E:\student121.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at scala.io.Source.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
… 32 elided

7、例外:Exception

类似于java,还是有一些变化
文件操作

scala> var words = scala.io.Source.fromFile("E:\\server.xml").mkString
words: String =
"<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership....
scala> val words = scala.io.Source.fromFile("E:\\212.txt").mkString
java.io.FileNotFoundException: E:\\212.txt(系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
... 32 elided

try catch finally练习

/**
* 1、采用 try catch finally 来捕获异常和处理异常
* 试验一下,scala中文件读取
*
*/
try{
// try 代码块里面写 可能抛出异常的函数
println("------------try catch finally------------------")
var words = scala.io.Source.fromFile("E:\\server.xml").mkString
println(words)
}catch {
case ex: FileNotFoundException => {
println("File Not Found Exception")
}
case ex: IllegalArgumentException =>{
println("Illegal Argument Exception")
}
case _:Exception =>{
println("This is an Exception")
}
}finally {
println("This is finally")
}
/**
* 当没有抛出异常时:
* try ---> finally
* 打印:
* This is finally
*
* 当抛出异常时:
* try --> catch --> finally
* File Not Found Exception
* This is finally
*/
/**
* 2、如果一个函数返回值类型是nothing,表示:在函数执行的过程中,产生了异常
*
* scala> def fun1() = throw new Exception("Exception")
* fun1: ()Nothing
*/

8、数组

1、数组的类型
(1)定长数组:Array

scala> val a = new Array[Int](10) -----> (10) 就是数组的长度
a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
scala> val a = new Array[String](10)
a: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)

初始化赋给默认值

scala> val c : Array[String] = Array("Tom","Lily")
c: Array[String] = Array(Tom, Lily)
scala> val c : Array[String] = Array("Tom","Lily",1)
<console>:11: error: type mismatch;
found : Int(1)
required: String
val c : Array[String] = Array("Tom","Lily",1)

不能往数组中添加不同类型的元素

(2)变长数组:ArrayBuffer

scala> val d = ArrayBuffer[Int]()
<console>:11: error: not found: value ArrayBuffer
val d = ArrayBuffer[Int]()
^

scala> import scala.collection.mutable._
import scala.collection.mutable._

mutable(可变的)

scala> val d = ArrayBufferInt
d: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()

scala> d += 1
res2: d.type = ArrayBuffer(1)

scala> d += 2
res3: d.type = ArrayBuffer(1, 2)

scala> d += (1,2,3,4)
res4: d.type = ArrayBuffer(1, 2, 1, 2, 3, 4)

scala> d.
++ combinations groupBy mapResult reverse to
++: companion grouped max reverseIterator toArray
++= compose hasDefiniteSize maxBy reverseMap toBuffer
++=: contains hashCode min runWith toIndexedSeq
+: containsSlice head minBy sameElements toIterable
+= copyToArray headOption mkString scan toIterator
+=: copyToBuffer indexOf nonEmpty scanLeft toList
- corresponds indexOfSlice orElse scanRight toMap
– count indexWhere padTo segmentLength toSeq
–= diff indices par seq toSet
-= distinct init partition size toStream
/: drop inits patch sizeHint toString
:+ dropRight insert permutations sizeHintBounded toTraversable
:\ dropWhile insertAll prefixLength slice toVector
<< endsWith intersect prepend sliding transform
WithFilter equals isDefinedAt prependAll sortBy transpose
addString exists isEmpty product sortWith trimEnd
aggregate filter isTraversableAgain readOnly sorted trimStart
andThen filterNot iterator reduce span union
append find last reduceLeft splitAt unzip
appendAll flatMap lastIndexOf reduceLeftOption startsWith unzip3
apply flatten lastIndexOfSlice reduceOption stringPrefix update
applyOrElse fold lastIndexWhere reduceRight sum updated
canEqual foldLeft lastOption reduceRightOption tail view
clear foldRight length reduceToSize tails withFilter
clone forall lengthCompare remove take zip
collect foreach lift repr takeRight zipAll
collectFirst genericBuilder map result takeWhile zipWithIndex

举例:去掉数组中,最后两个元素
scala> d
res5: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 1, 2, 3, 4)
scala> d.trimEnd(2)
scala> d
res7: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 1, 2)
遍历数组:
for循环、foreach:
scala> var a = Array("Tom","Lily","Andy")
a: Array[String] = Array(Tom, Lily, Andy)
scala> for(s <- a ) println(s)
Tom
Lily
Andy
scala> a.foreach(println)
Tom
Lily
Andy
数组的常见操作举例:
scala> val myarray = Array(1,2,7,8,10,3,6)
myarray: Array[Int] = Array(1, 2, 7, 8, 10, 3, 6)
scala> myarray.max
res10: Int = 10
scala> myarray.min
res11: Int = 1
scala> myarray.sortWith(_>_)
res12: Array[Int] = Array(10, 8, 7, 6, 3, 2, 1)
scala> myarray.sortWith(_<_)
res13: Array[Int] = Array(1, 2, 3, 6, 7, 8, 10)
解释:(_>_)
完整 : sortWith函数里面,参数也是一个函数 --> 高阶函数
_>_ 函数
def comp(a:Int,b:Int) = {if(a>b) true else false}
(a,b) => {if(a>b) true else false}
(a,b) => {if(a>b) true else false} ----> _>_
_>_ 是一个函数,传入两个参数,返回值是bool (布尔型)

2、多维数组
和java类似,通过数组的数组来实现

scala> var matrix = Array.ofDim[Int](3,4)
matrix: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0))
Array(0, 0, 0, 0)
Array(0, 0, 0, 0)
Array(0, 0, 0, 0)

三行四列的数组

scala> matrix(1)(2)=10

scala> matrix
res15: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 10, 0), Array(0, 0, 0, 0))

数组下标是从0开始的

例子:
定义一个二维数组,其中每个元素是一个一维数组,并且长度不固定

scala> var triangle = new Array[Array[Int]](10)
triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)

初始化:

scala> for(i <- 0 until triangle.length){
| triangle(i) = new Array[Int](i+1)
| }

scala> triangle
res17: Array[Array[Int]] = Array(Array(0), Array(0, 0), Array(0, 0, 0),
Array(0, 0, 0, 0), Array(0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0, 0), Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))

二维数组,如果使用 ArrayArray[Int] 声明时:
1、首先指定的是外层数据的长度
2、初始化内层数组的时候,再指定内层数组的长度

9、映射 <key,value> Map

举例:
创建一个map,来保存学生的成绩

scala> val scores = Map(“Tom” -> 80,”Andy”->70,”Mike”->90)
scores: scala.collection.mutable.Map[String,Int] = Map(Mike -> 90, Tom -> 80, Andy -> 70)

1、Map[String,Int] key String value Int
2、scala.collection.mutable

scala中,映射是有两种,一种是可变map,一种是不可变map
scala.collection.mutable —> 可变
scala.collection.immutable —> 不可变

scala> val scores2 = scala.collection.immutable.Map(“Tom” -> 80,”Andy”->70,”Mike”->90)
scores2: scala.collection.immutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70, Mike -> 90)

映射的初始化:
scala> val scores2 = scala.collection.mutable.Map((“Tom”,80),(“Andy”,70))
scores2: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70)

scala> scores2=1
<console>:15: error: reassignment to val
scores2=1

映射的操作:

1、获取映射中的值

scala> val chinese = scala.collection.mutable.Map(("Tom",80),("Andy",70))
chinese: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70)
scala> chinese("Tom")
res18: Int = 80
scala> chinese.get("Andy")
res19: Option[Int] = Some(70)
scala> chinese("aaaa")
java.util.NoSuchElementException: key not found: aaaa
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.mutable.HashMap.apply(HashMap.scala:65)
... 32 elided
scala> chinese.get("Andy1231312")
res21: Option[Int] = None
chinese("aaaa") get("Andy1231312")
需求:判断key是否存在,若不存在,返回默认值
scala> if(chinese.contains("aaa")){
| chinese("aaa")
| }else{
| -1
| }
res22: Int = -1
scala> chinese.getOrElse("aaaa",-1)
res23: Int = -1

2、更新映射中的值

注意:必须是可变映射
scala> chinese
res24: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 70)
scala> chinese("Andy")=20
scala> chinese
res26: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 20)

3、映射的迭代
for foreach

scala> chinese
res27: scala.collection.mutable.Map[String,Int] = Map(Tom -> 80, Andy -> 20)
scala> for(s<-chinese) println(s)
(Tom,80)
(Andy,20)
scala> chinese.foreach(println)
(Tom,80)
(Andy,20)
foreach 高阶函数

10、元组 : Tuple

scala 中的tuple : 是不同类型值的集合
scala> val t1 = Tuple("Tom","Lily",1)
<console>:14: error: not found: value Tuple
val t1 = Tuple("Tom","Lily",1)
^
-----Tuple需要指明不同类型值的个数
scala> val t1 = Tuple3("Tom","Lily",1)
t1: (String, String, Int) = (Tom,Lily,1)
Tuple3 代表 Tuple中有三个元素
scala> val t1 = Tuple2("Lily",1)
t1: (String, Int) = (Lily,1)
scala> val t2 = (1,2,4,"Hello")
t2: (Int, Int, Int, String) = (1,2,4,Hello)
tuple操作:
访问tuple中的元素
scala> val t1 = Tuple3("Tom","Lily",1)
t1: (String, String, Int) = (Tom,Lily,1)
scala> t1.
_1 _3 copy hashCode productArity productIterator toString zipped
_2 canEqual equals invert productElement productPrefix x
scala> t1._1
res30: String = Tom
scala> t1._3
res31: Int = 1
如何遍历Tuple中的元素
注意:Tuple并没有提供一个foreach函数,我们使用productIterator
遍历分为两步:
1、使用 productIterator 生成一个迭代器
2、遍历
scala> t1.productIterator.
!= copyToBuffer forall min reduceRightOption toIterable
## corresponds foreach minBy sameElements toIterator
+ count formatted mkString scanLeft toList
++ drop getClass ne scanRight toMap
-> dropWhile grouped next seq toSeq
/: duplicate hasDefiniteSize nonEmpty size toSet
:\ ensuring hasNext notify slice toStream
== eq hashCode notifyAll sliding toString
GroupedIterator equals indexOf padTo span toTraversable
addString exists indexWhere partition sum toVector
aggregate filter isEmpty patch synchronized wait
asInstanceOf filterNot isInstanceOf product take withFilter
buffered find isTraversableAgain reduce takeWhile zip
collect flatMap length reduceLeft to zipAll
collectFirst fold map reduceLeftOption toArray zipWithIndex
contains foldLeft max reduceOption toBuffer →
copyToArray foldRight maxBy reduceRight toIndexedSeq
scala> t1.productIterator.foreach(println)
Tom
Lily
1

11、scala中的文件操作

类似于java的io
举例:
1、读取文件
2、读取二进制文件
3、从url中获取信息
4、写入文件
5、scala中调用java的类库

代码练习

//读取文件中的行
var source = fromFile("E:\\server.xml")
/**
* 1、将整个文件作为字符串输出
*
* 2、将文件的每一行读入输出
*/
println("--------mkString------------------")
//println(source.mkString)
println("----------lines-------------------")
//var lines = source.getLines()
//lines.foreach(println)
println("-----------读取字符----------------")
//for (c <- source) println(c)
println("-----------读取字URL----------------")
var source2 = fromURL("https://hsiehchou.com","UTF-8")
println(source2.mkString)
/**
* 注意:scala中并不支持直接读取二进制文件
*
* 通过调用java的InputStream来实现
*/
println("-----------读取二进制文件----------------")
//var file = new File("E:\\hsiehchou.war")
//构造一个inputstream
//var in = new FileInputStream(file)
//构造一个buffer
// var buffer = new Array[Byte](file.length().toInt)
//读取
//in.read(buffer)
//println(buffer.length)
//关闭
//in.close()
/**
* 写文件
*/
println("---------Write File----------------")
var out = new PrintWriter("E:\\insert.txt")
for(i <- 0 until 10) out.println(i)
out.close()

二、Scala面向对象

scala是一个多范式的编程语言(支持多种方式的编程)
类似于java 有区别

1、面向对象的概念

1、封装 : 把属性和操作属性的方法,写在了一起。class
2、继承
3、多态

java中面向对象的概念,也是用与scala

2、定义类:class

举例:创建一个学生类

package day3
/**
* 学生
*/
class Student1 {
//定义学生的属性
private var stuId:Int =0
private var stuName:String = "Time"
private var age:Int = 20
//定义方法(函数)get set
def getStuName():String = stuName
def setStuName(newName:String) = this.stuName = newName
def getStuAge():Int = age
def setStuAge(age:Int) = this.age = age
}
/**
* 注意object 和 class名字可以不一样
*
* 如果一样的话,这个object就叫作class的伴生对象
*/
object Student1{
def main(args: Array[String]): Unit = {
//测试
//创建一个学生对象
var s1 = new Student1
//访问他的属性并输出
println(s1.getStuName()+"\t"+s1.getStuAge())
//访问set方法
s1.setStuName("Hsieh")
s1.setStuAge(23)
println(s1.getStuName()+"\t"+s1.getStuAge())
//直接访问私有属性
println("-------访问私有属性----------")
println(s1.stuId+"\t"+s1.stuName+"\t"+s1.age)
/**
* 为什么我们可以访问私有成员
*
* s1.stuId
*
* 属性的set get 方法
* 1、当一个属性是private属性的时候,scala会自动为其生成set get方法
*
* s1.stuId .stuId调用了get方法 get 方法的名字就叫stuId
*
* 2、如果只希望生成get方法而不生成set方法,可以定义成常量
*
* 3、如果希望属性不能被外部访问,使用private[this]关键字
*/
}
}

3、内部类(嵌套类)

在一个类的内部,定义了另外一个类

package day3
import scala.collection.mutable.ArrayBuffer
/**
* 需求:定义一个学生类,同时要保存学生的成绩信息
*/
class Student2 {
//定义学生的属性
private var stuName : String = "Time"
private var stuAge : Int = 23
//定义一个数组,来保存学生的课程成绩信息
private var courseList = new ArrayBuffer[Course]()
//定义一个函数,用于添加学生课程成绩
def addNewCourse(cname:String, grade:Int): Unit = {
//创建课程成绩信息
var c = new Course(cname,grade)
//添加到学生
courseList += c
}
//定义课程类
class Course(var courseName:String, var grade : Int){
}
}
object Student2{
def main(args: Array[String]): Unit = {
//创建学生对象
var s = new Student2
//给学生添加课程信息
s.addNewCourse("Chinese",78)
s.addNewCourse("English",80)
s.addNewCourse("Math",90)
println(s.stuName+"\t"+s.stuAge)
println("-----------课程信息------------")
for(c<-s.courseList) println(c.courseName+"\t"+c.grade)
}
}

4、类的构造器:两种

1、主构造器 : 和类的声明在一起,并且一个类只能有一个主构造器
class Course(var courseName:String,var grade : Int)

2、辅助构造器 : 一个类可以有多个辅助构造器,通过this来实现

5、object对象

相当于java中的static
1、Object 对象中的内容都是静态的
2、如果和类名相同,则成为伴生对象
3、scala中没有static关键字
4、举例
(1)使用object来实现单例模式:一个类里面只有一个对象
在java中,把类的构造器定义成private的,并且提供一个getInstance,返回对象

在scala中,使用object实现
例子:

package day3
/**
* 实现单例模式
*/
object CreditCard {
//定义一个变量来保存信用卡卡号
private [this] var creditCardNumber : Long = 0
//定义一个函数产生卡号
def generateNum : Long = {
creditCardNumber += 1
creditCardNumber
}
def main(args: Array[String]): Unit = {
println(CreditCard.generateNum)
println(CreditCard.generateNum)
println(CreditCard.generateNum)
println(CreditCard.generateNum)
}
}

(2)使用App对象:应用程序对象
好处:可以省略main方法
例子:

package day3
object HelloWorld extends App{
// def main(args: Array[String]): Unit = {
// println("Hello World!")
// }
println("Hello World!")
if(args.length>0){
println("有参数")
}else{
println("没有参数")
}
}

6、apply方法

val t1 = Tuple3(“Tom”,”Lily”,1)
没有new关键字,但是也创建出来对象,用了apply方法

package day3
class Student4(var stuName:String)
/**
* 定义Student4的apply方法
*/
object Student4 {
def apply(name:String) = {
println("调用apply方法")
new Student4(name)
}
def main(args: Array[String]): Unit = {
//通过主构造器来创建学生对象
var s1 = new Student4("Time")
println(s1.stuName)
//通过apply方法来创建学生对象,省略new 关键字
var s2 = Student4("Hsiehchou")
println(s2.stuName)
}
}

注意:apply方法必须写在伴生对象中

7、继承

1)extends 和java一样
object HelloWorld extends App

package day3
/**
* extends 继承
*
* 父类:Person 人
* 子类:Employee员工
*/
//定义父类
class Person(val name:String,val age:Int){
//定义函数
def sayHello():String = "Hello "+name+" and the age is "+age
}
//定义子类
class Employee(override val name:String,override val age:Int,salary:Int) extends Person(name,age){
//重写父类中的函数
override def sayHello(): String = "子类中的sayHello"
}
object Demo1 extends App {
//创建Person
var p1 = new Person("Tim",23)
println(p1.name+"\t"+p1.age)
println(p1.sayHello())
//创建一个子类对象
var p2:Person = new Employee("Nike",35,1000)
println(p2.sayHello())
//匿名子类
var p3:Person = new Person("Jike",32){
//在匿名子类中重写sayHello方法
override def sayHello(): String = "匿名子类中的sayHello"
}
println(p3.sayHello())
}

2)抽象类

package day3
/**
* 抽象类:只能用于继承的类,可以包含抽象方法
*/
//父类:交通工具类
abstract class Vehicle {
//定义抽象方法,没有实现的方法
def checkType():String
}
//子类:自行车、汽车
class Car extends Vehicle{
def checkType : String = "I am a car"
}
class Bike extends Vehicle{
def checkType : String = "I am a bike"
}
object Demo2{
def main(args: Array[String]): Unit = {
//多态
var v1 : Vehicle = new Car
println(v1.checkType())
var v2 : Vehicle = new Bike
println(v2.checkType())
}
}

3)抽象字段

package day3
/**
* 抽象字段 抽象属性
*
* 定义:没有初始值的字段
*/
abstract class Person1{
//定义抽象字段
val id:Int
val name:String
}
//如果不加abstract 报错
abstract class Employee1 extends Person1{
}
//下面两种方式均不会报错
class Employee2() extends Person1{
val id:Int = 1
val name:String = "Time"
}
class Employee3(val id:Int,val name:String) extends Person1{
}
object Demo3 {
}

8、特质(trait)

抽象类,支持多重继承
本质:scala 的一个抽象类
trait

package day4
/**
* trait特质
*
* 定义两个父类,就是两个trait
*
* 父类:人、动作
*
* 子类:学生
*/
trait Human{
//抽象字段
val id:Int
val name:String
}
//动作
trait Action{
//定义一个抽象函数
def getActionName():String
}
class Student1(val id:Int,val name:String) extends Human with Action{
override def getActionName(): String = "Action is running"
/**
* 实现多重继承的方式 extends Human with Action
*/
}
object Demo1 {
def main(args: Array[String]): Unit = {
//创建一个学生对象
var s1 = new Student1(1,"Time")
println(s1.id+"\t"+s1.name)
println(s1.getActionName())
}
}

关键字:extends Human with Action
`

9、包和包对象

package
package object

Scala中包的定义和使用

  1. 包的定义
    1)首先是Scala中的包可以像Java一样使用,例如:

package com.my.io
class XXX

2)可以像C#的namespace一样使用package语句,例如:

package com.my.io{
class XXX
}

3)package也是可以嵌套的,例如:

package com.my.io{
class XXX
package test{
class T
}
}
  1. 包的引入:Scala中依然使用import作为引用包的关键字,例如
    import com.my.io.XXX //可以不写XXX的全路径
    import com.my.io._ //引用import com.my.io下的所有类型
    import com.my.io.XXX._ //引用import com.my.io.XXX的所有成员

  2. 而且Scala中的import可以写在任意地方

def method(fruit:Fruit){
import fruit._
println(name)
}

包对象
包可以包含类、对象和特质,但不能包含函数或者变量的定义。很不幸,这是Java虚拟机的局限

把工具函数或者常量添加到包而不是某个Utils对象,这是更加合理的做法。Scala中,包对象的出现正是为了解决这个局限

Scala中的包对象:常量,变量,方法,类,对象,trait(特质)

package class4
/**
* Scala中的包对象:常量、变量、方法、类、对象、trait(特质)
*/
//定义一个包对象
package object MyPackageObject{
//常量
val x:Int = 0
//变量
var y:String = "Hello World"
//方法
def sayHelloWorld():String = "Hello World"
//类
class MyTestClass{
}
//对象object
object MyTestObject{
}
//trait(特质)
trait MyTestTrait{
}
}
class Demo3{
//测试
def method1() = {
//导入需要的包对象
import class4.MyPackageObject._
//定义MyTestClass的一个对象
var a = new MyTestClass
}
}

以上是关于Scala基础的主要内容,如果未能解决你的问题,请参考以下文章

大数据学习06 Scala的基础语法

Scala 基础语法

「大数据」(八十六)Scala基础

Scala学习之路----基础入门

初学scala4——trait混入

Scala附加列表