- 浏览: 622195 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (334)
- java core (12)
- struts2.x (2)
- spring (3)
- hibernate (8)
- jpa (6)
- maven (2)
- osgi (5)
- eclipse (4)
- struts2.x+spring2.x+hibernate 整合 (5)
- ebs (0)
- html (0)
- vaadin (1)
- css (0)
- jquery (0)
- javascript (0)
- svn (1)
- cvs (0)
- axas2.x (0)
- eclipse+maven (9)
- annotation (0)
- 基于OSGi的动态化系统搭建 (1)
- notenet (1)
- jboss eclipse (4)
- eclipse工具 (4)
- jdk1.6+maven3.0.3+nuxeo+svn+felix+cxf+spring+springDM (6)
- spring dm (1)
- Nexus介绍 (1)
- proxool listener (0)
- oracle (4)
- mysql (8)
- 搭建你的全文检索 (1)
- hibernatehibernatehibernate (0)
- cvsearchcvsearch (0)
- mycvseach (0)
- asdfasdfasdf (0)
- propertiey (0)
- hibernate annotation (0)
- libs (0)
- icam (2)
- start 数据库配置 (0)
- jboss (1)
- 让Eclipse启动时显示选择workspace的对话框 (1)
- table表头固定 (1)
- s2s3h4 (0)
- leaver (0)
- mycvsaerchddd (0)
- 关于jboss5.0.1部署 (4)
- bookmarks (0)
- PersistenceUnitDeployment (0)
- mycom (0)
- HKEY_CURRENT_USER = &H80000001 (0)
- syspath (1)
- css div (1)
- Dreamweaver CS5 (0)
- generate (0)
- mysql查看表结构命令 (1)
- LOG IN ERROR EMAIL TO SB (0)
- struts2 handle static resource (1)
- jsf (2)
- log4j (1)
- jbpm4.4 (2)
- down: jbpm4.4 (1)
- jstl1.2 (1)
- spring annotation (1)
- java design pattern (1)
- cache (1)
- ehcache (1)
- 11111 (0)
- myge (0)
- pom.xml (0)
- springquartz (0)
- OpenStack (9)
- hadoop (2)
- nginx (1)
- hadoop openstack (1)
- os (1)
- hadoop-2.6.0 zookeeper-3.4.6 hbase-0.98.9-hadoop2 集群 (5)
- hadoop2.7.0 ha Spark (2)
- tess (0)
- system (1)
- asdf (0)
- hbase (2)
- hbase create table error (1)
- ekl (1)
- gitignore (1)
- gitlab-ci.yml (1)
- shell (1)
- elasticsearch (2)
- Azkaban 3.0+ (1)
- centos用命令 (1)
- hive (1)
- kafka (1)
- CaptureBasic (0)
- CentOS7 (1)
- dev tools (1)
- README.md (1)
- Error (1)
- teamviewerd.service (1)
- scala (1)
- spark (1)
- standard (1)
- gitlab (1)
- IDEA (0)
- ApplicationContext (1)
- 传统数仓 (1)
- redis install (1)
- MYSQL AND COLUME (1)
- java版本选择 (1)
- hue (1)
- npm (1)
- es (1)
- 版本管理 (1)
- 升级npm版本 (1)
- git (1)
- 服务器参数设置 (1)
- 调大 IDEA 编译内存大小 (0)
- CentOS8安装GitLab (1)
- gitlab安装使用 (1)
最新评论
-
ssydxa219:
vim /etc/security/limits.confvi ...
ekl -
Gamehu520:
table中无数据
hbase 出现的问题 -
Xleer0102:
为什么都是只有问没有答,哭晕在厕所
hbase 出现的问题 -
jiajiao_5413:
itext table -
CoderDream:
不完整,缺com.tcs.org.demostic.pub.u ...
struts2.3.1.1+hibernate3.6.9Final+spring3.1.0+proxool+maven+annotation
一、Scala解释器的使用
REPL:Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)
scala解释器也被称为REPL,会快速编译scala代码为字节码,然后交给JVM来执行。
计算表达式:在scala>命令行内,键入scala代码,解释器会直接返回结果。
如果你没有指定变量来存放这个值,那么值默认的名称为res,而且会
显示结果的数据类型,比如Int、Double、String等等。
例如,输入1 + 1,会看到res0: Int = 2
内置变量:在后面可以继续使用res这个变量,以及它存放的值。
例如,"Hi, " + res0,返回res2: String = Hi, 2
自动补全:在scala>命令行内,可以使用Tab键进行自动补全。
二、声明变量
声明val常量:可以声明val常量来存放表达式的计算结果。
例如,val result = 1 + 1
但是常量声明后,是无法改变它的值的,否则会返回error: reassignment
to val的错误信息。
声明var变量:如果要声明值可以改变的引用,可以使用var变量。
例如,var myresult = 1,myresult = 2
但是在Scala程序中,通常建议使用val,也就是常量。
因为在Spark的大型复杂系统中,需要大量的网络传输数据,
如果使用var,值可能被错误的更改,所以建议多使用val。
三、数据类型与操作符
1》基本数据类型: Byte、 Char、 Short、 Int、 Long、 Float、 Double、 Boolean。
Scala的数据类型统一都是类。 Scala自己会负责基本数据类型和引用类型的转换操作。
使用以上类型, 直接就可以调用大量的函数, 例如, 1.toString(), 1.to(10)。
类型的加强版类型: Scala使用很多加强类给数据类型增加了上百种增强的功能或函数。
·例如, String类通过StringOps类增强了大量的函数, "Hello".intersect(" World")。
·例如, Scala还提供了RichInt、 RichDouble、 RichChar等类型, RichInt就提供了to函数, 1.to(10), 此处Int先隐式转换为RichInt,然后再调用其to函数。
2》基本操作符: Scala的算术操作符与Java的算术操作符也没有什么区别, 比如+、 -、 *、 /、 %等, 以及&、 |、 ^、 >>、 <<等。
但是, 在Scala中, 这些操作符其实是数据类型的函数, 比如1 + 1, 可以写做1.+(1)
例如, 1.to(10), 又可以写做1 to 10
注:Scala中没有提供++、--操作符, 我们只能使用+和-, 比如counter = 1,counter++是错误的, 必须写做counter += 1
3》除了方法之外,Scala还提供函数
数学函数:sqrt() pow() min()
引入特定包时使用import 包名._;
import scala.math._ ,_是通配符,类似Java中的*
四、流程控制结构
1、if表达式的定义: 在Scala中, if表达式是有值的, 就是if或者else中最后一行语句返回的值。
例如, val age = 30; if (age > 18) 1 else 0
可以将if表达式赋予一个变量, 例如, val isAdult = if (age > 18) 1 else 0
另外一种写法, var isAdult = -1; if(age > 18) isAdult = 1 else isAdult = 0, 但是通常使用上一种写法
2、if表达式的类型推断: 由于if表达式是有值的, 而if和else子句的值类型可能不同, 此时if表达式的值是什么类型呢?
Scala会自动进行推断, 取两个类型的公共父类型Any。
例如, if(age > 18) 1 else 0, 表达式的类型是Int, 因为1和0都是Int
例如, if(age > 18) "adult" else 0, 此时if和else的值分别是String和Int, 则表达式的值是Any, Any是String和Int的公共父类型。
如果if后面没有跟else, 则默认else的值是Unit, 也用()表示, 类似于Java中的void或者null。
例如, val age = 12; if(age > 18) "adult"。 此时就相当于if(age > 18) "adult" else ()。
3、将if语句放在多行中: 默认情况下, REPL只能解释一行语句, 但是if表达式通常需要放在多行。
可以使用{}的方式, 比如以下方式, 或者使用:paste和ctrl+D的方式。
if(age > 18) { "adult"
} else if(age > 12) "teenager" else "children"
注:默认情况下, Scala不需要语句终结符, 默认将每一行作为一个语句
4、一行放多条语句: 如果一行要放多条语句, 则必须使用语句终结符
例如, 使用分号作为语句终结符, var a, b, c = 0; if(a < 10) { b = b + 1;c = c + 1 }
通常来说, 对于多行语句, 还是会使用花括号的方式
var a, b, c = 0;if(a < 10) {
b = b + 1;c = c + 1}
5、块表达式: 块表达式, 指的就是{}中的值, 其中可以包含多条语句, 最后一个语句的值就
是块表达式的返回值。
例如, var d = if(a < 10) { b = b + 1; c + 1 }
6、输入和输出
print和println: print打印时不会加换行符, 而println打印时会加一个换行符。
printf可以用于进行格式化,例如, printf("Hi, my name is %s, I'm %d years old .", "Leo", 30)
readLine: readLine允许我们从控制台读取用户输入的数据, 类似于Java中的System.in和Scanner的作用。
综合案例:使用paste和ctrl+D
val name = readLine("Welcome to Game House. Please tell me your name: ")
print("Thanks. Then please tell me your age: ")
val age = readInt()
if(age > 18) {
printf("Hi, %s, you are %d years old, so you are legel to come here!", name, age)
} else {
printf("Sorry, boy, %s, you are only %d years old. you are illegal to come here!",
name, age)
}
五、循环
1、Scala拥有与Java相同的while和do-while循环
但没有与for(初始化变量;判断条件;更新变量)循环直接对应的对构。
Scala中的for:for(i<-表达式),让变量i遍历<-右边表达式的所有值。
注意:
1、在for循环的变量之前并没有val或var的指定,该变量的类型是集合的元素类型。
2、循环变量的作用域一直持续到循环结束
3、to 和 until,两者得到都是集合,区别如下:
scala> 1 to 10 (包含10)
res8: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> 1 until 10 (不包含10)
res10: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
4、循环的几种遍历方式
一、直接遍历------遍历字符串
二、求和---------1到8的和
三、以 变量<-表达式 的形式提供多个生成器,用分号将它们隔开(嵌套循环)
for(i<- 1 to 9;j<- 1 to i){
if(i==j) println(j+"*"+i+"="+j*i)
else print(j+"*"+i+"="+j*i+"\t")
}
四、在循环中使用变量
for(i<- 1 to 6;tem=2*i-1;j<- 1 to tem){
print("*");if(j==tem) {println()}}
五、守卫式,即在for循环中添加过滤条件if语句
for(i<- 1 to 3;j<- 1 to 3 if i!=j) print((10*i+j)+" ")
六、推导式
如果for循环的循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值。
六、函数
1、函数的分类
单行函数:def sayHello(name: String) = print("Hello, " + name)
多行函数:如果函数体中有多行代码, 则可以使用代码块的方式包裹多行代码, 代码块中最后一行
的返回值就是整个函数的返回值。 与Java中不同, 不能使用return返回值。
比如如下的函数, 实现累加的功能:
def sum(n: Int) :Int= {
var sum = 0;
for(i <- 1 to n) sum += i
sum}
2、函数的定义与调用
在Scala中定义函数时, 需要定义函数的函数名、 参数、 函数体。
def sayHello(name: String, age: Int) = {
if (age > 18) { printf("hi %s, you are a big boy\n", name); age }
else { printf("hi %s, you are a little boy\n", name); age}}
调用:sayHello("leo", 30)
注:Scala要求必须给出所有参数的类型, 但是不一定给出函数返回值的类型。
只要右侧的函数体中不包含递归的语句, Scala就可以自己根据右侧的表达式推断出返回类型。
3、递归函数与返回类型
如果在函数体内递归调用函数自身, 则必须给出函数的返回类型。
例如, 实现经典的斐波那契数列:
def feibo(n:Int):Int={
if(n<=2) 1
else feibo(n-1)+feibo(n-2)}
例如如下阶乘:
4、参数
1》默认参数
在Scala中, 有时我们调用某些函数时, 不希望给出参数的具体值, 而希望使用参数自身默认的值, 此时就在定义函数时使用默认参数。
def sayHello(firstName: String, middleName: String = "William", lastName:
String = "Croft") = firstName + " " + middleName + " " + lastName
如果给出的参数不够, 则会从左往右依次应用参数。
Java与Scala实现默认参数的区别如下:
-----------------------------------------------------------------------------------
Java:
public void sayHello(String name, int age) {
if(name == null) {
name = "defaultName"
} if(age == 0) {
age = 18
}}
sayHello(null, 0)
-----------------------------------------------------------------------------------
Scala:
def sayHello(name: String, age: Int = 20) {
print("Hello, " + name + ", your age is " + age)}
sayHello("leo")
2》带名参数
在调用函数时, 也可以不按照函数定义的参数顺序来传递参数, 而是使用带名参数的方式来
传递。如:sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack")
还可以混合使用未命名参数和带名参数, 但是未命名参数必须排在带名参数前面。如下:
正确:sayHello("Mick", lastName = "Nina", middleName = "Jack")
错误:sayHello("Mick", firstName = "Nina", middleName = "Jack")
3》使用序列调用变长参数
在如果要将一个已有的序列直接调用变长参数函数, 是不对的。 比如val s = sum(1 to 5)。
此时需要使用Scala特殊的语法将参数定义为序列, 让Scala解释器能够识别。
这种语法非常有用!Spark的源码中大量地使用。
例如:val s = sum(1 to 5 : _*) 通过:_*转换成参数序列
案例: 使用递归函数实现累加,如下:
def sum2(nums: Int*): Int = {
if (nums.length == 0) 0
else nums.head + sum2(nums.tail: _*)
}
调用:sum2(1,2,3,4,5) 或是 sum2(1 to 5 :_*)
注:1、定义nums为一个变长参数,定义函数时用*,调用函数需要表示一个参数序列时用:_*
2、head 表示集合中的第一个元素,tail 表示集合中除了第一个元素外的其他元素
七、过程
定义:在Scala中, 定义函数时, 如果函数体直接包裹在了花括号里面, 而没有使用=连接,
则函数的返回值类型就是Unit, 这样的函数就被称之为过程。过程通常用于不需要返回值的函数。
过程还有一种写法, 就是将函数的返回值类型定义为Unit。比较如下:
def sayHello(name: String) = "Hello, " + name
def sayHello(name: String) { print("Hello, " + name); "Hello, " + name }
def sayHello(name: String): Unit = "Hello, " + name
八、lazy值
在Scala中, 提供了lazy值的特性, 也就是说, 如果将一个变量声明为lazy, 则只有在第一次使用
该变量时, 变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用, 比如打开文件进行IO, 进行网络IO等。
1、import scala.io.Source._
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
即使文件不存在, 也不会报错, 只有第一次使用变量时会报错, 证明了表达式计算的lazy特性
val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString 这句会报错
2、val lines=sc.textFile("file:///home/tg/datas/ws")
val rdd1=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
val rdd2=rdd1.collect
算子: flatMap() map() reduceByKey()转换类型的算子(transformation)
collect()行动类型的算子(action)
3、val rdd=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).map(m=>(m._2,m._1))
.sortByKey(true).map(m=>(m._2,m._1)).collect
注:转换类型的算子就是lazy类型,当遇到action行动类型的算子时,才会触发执行。
总结下划线的用法:
1、导包时,导入包中所有内容 import scala.io.Source._
2、将数列(集合)转换成参数序列 val result=sum(1 to 10:_*)
3、表示Spark算子操作的每一个元素 lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
八、异常
在Scala中, 异常处理和捕获机制与Java是非常相似的。
try {
throw new IllegalArgumentException("x should not be negative")
} catch {
case _:IllegalArgumentException => println("Illegal Argument!")
} finally {
print("release resources!")
}
try {
throw new IOException("user defined exception")
} catch {
case e1:IllegalArgumentException => println("illegal argument")
case e2:IOException => println("io exception")
}
九、数组
若数组长度固定使用Array,若数组长度不固定则使用ArrayBuffer
1、定长数组的两种创建方式
1》val nums=new Array[Int](10); //10个整数的数组 2》val array=Array("hello","jack")
省略关键字new创建数组的方式,实际上调用的是 Array.scala中的apply()方法。源码如下:
def apply[T: ClassTag](xs: T*): Array[T] = {
val array = new Array[T](xs.length)
var i = 0
for (x <- xs.iterator) {
array(i) = x;
i += 1 }
array}
2、变长数组:数组缓冲
注:scala.collection.mutable._ 可变 scala.collection.immutable._ 不可变
对于那种长度按需要变化的数组,Java有ArrayList,Scala有ArrayBuffer
变长数组ArrayBuffer使用时要导包 import scala.collection.mutable.ArrayBuffer
var arr1=ArrayBuffer[Int]()
变长数组操作:1、arr1+=1 2、arr1+=(2,5,6) 3、arr1 ++=Array(3,4)
4、arr1.trimEnd(5) 返回值为空,需再次调用arr1来查看删除后的数据
5、arr1.insert(1,3,4) 指定1的位置添加3,4元素
6、arr1.remove(3)
7、arr1.remove(3,2) 指定位置删除指定数量的元素
3、变长数组与定长数组之间的转换
变长数组→定长数组:.toArray (不改变原来的数组,系统会自动创建一个新的arry)
定长数组→变长数组:.toBuffer
4、遍历数组
until是RichInt类的方法, 返回所有小于( 不包括) 上限的数字。
5、数组常用算法
,除了sum求和,max最大值,min最小值以外还有如下:
6、数组的quickSort()快速排序方法scala.util.Sorting.quickSort(array)
十、高阶函数
filter :把一个函数作为参数的函数
for(i <- 0 until arr1.length if(arr1(i)%2==0)) print(arr1(i)+" ")
array.filter(m=>m%2==0) 这里的m可以省去简写成 array.filter(_%2==0)
m=>m%2==0 匿名函数 m=>{m%2==0}
算子: spark中的算子有一部分是和scala中的高阶函数是一致的,
但是有一部分是scala中没有的,比如reducekey
简写用下划线代替m: val rdd=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
lines.flatMap(m=>m.split(" ")).map(word=>(word,1)).reduceByKey((x,y)=>x+y)
十一、映射(Map)
1、Scala映射就是键值对的集合Map。默认情况下,Scala中使用不可变的映射。
如果想使用可变集合Map,必须导入scala.collection.mutable.Map
不可变:
val map=Map("tom"->20,"jack"->23,"marray"->22)
val map2=Map(("tom",20),("jack",23),("marray",22))
可变:
val map3=scala.collection.mutable.Map(("tom",20),("jack",23),("marray",22))
val map4=new scala.collection.mutable.HashMap[String,Int]
映射这种数据结构是一种将键映射到值的函数。 区别在于通常的函数计算值, 而映射只是做查询。
2、获取映射中的值
注:1》如果映射并不包含请求中使用的键, 则会抛出异常。
2》要检查映射中是否有某个指定的键, 可以用contains方法。
3》getOrElse方法, 若包含相应的键, 就返回这个键所对应的值, 否则返加0。
4》映射.get(键)这样的调用返回一个Option对象, 要么是Some(键对应的值), 要么是None。
3、修改Map的元素
更新可变Map集合:
1》更新Map的元素 ages("Leo") = 31
2》增加多个元素 ages += ("Mike" -> 35, "Tom" -> 40)
3》 移除元素 ages -= "Mike"
更新不可变Map集合:
1》 添加不可变Map的元素, 产生一个新的集合Map, 原Map不变
val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)
2》移除不可变Map的元素, 产生一个新的集合Map, 原Map不变
val ages3 = ages - "Tom"
4、遍历Map操作
//遍历map的entrySet for ((key, value) <- ages) println(key + " " + value)
// 遍历map的key for (key <- ages.keySet) println(key)
// 遍历map的value for (value <- ages.values) println(value)
// 生成新map, 反转key和value for ((key, value) <- ages) yield (value, key)
5、SortedMap和LinkedHashMap
// SortedMap可以自动对Map的key的排序
val ages = scala.collection.immutable.SortedMap("leo" -> 30, "alice" -> 15, "jen" -> 25)
// LinkedHashMap可以记住插入entry的顺序
val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
ages("leo") = 30
ages("alice") = 15
ages("jen") = 25
6、Java Map与Scala Map的隐式转换
import scala.collection.JavaConversions.mapAsScalaMap
val javaScores = new java.util.HashMap[String, Int]()
javaScores.put("Alice", 10)
javaScores.put("Bob", 3)
javaScores.put("Cindy",
val scalaScores: scala.collection.mutable.Map[String, Int] = javaScores
===========================================================
import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute._
val scalaAttrMap = Map(FAMILY -> "Serif", SIZE -> 12)
val font = new java.awt.Font(scalaAttrMap)
7、元组(tuple)
概念:元组是不同类型的值的聚集,对偶是元组的最简单形态,元组的索引从1开始,而不是0
Tuple拉链操作:
Tuple拉链操作指的就是zip操作,zip操作是Array类的方法, 用于将两个Array, 合并为一个Array
比如 Array(v1)和Array(v2), 使用zip操作合并后的格式为Array((v1,v2)),合并后的Array的元素类型为Tuple。例子如下:
val students = Array("Leo", "Jack", "Jen")
val scores = Array(80, 100, 90)
val studentScores = students.zip(scores)
for ((student, score) <- studentScores) println(student + " " + score)
注:如果Array的元素类型是Tuple, 调用Array的toMap方法, 可以将Array转换为Map
如,studentScores.toMap
REPL:Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)
scala解释器也被称为REPL,会快速编译scala代码为字节码,然后交给JVM来执行。
计算表达式:在scala>命令行内,键入scala代码,解释器会直接返回结果。
如果你没有指定变量来存放这个值,那么值默认的名称为res,而且会
显示结果的数据类型,比如Int、Double、String等等。
例如,输入1 + 1,会看到res0: Int = 2
内置变量:在后面可以继续使用res这个变量,以及它存放的值。
例如,"Hi, " + res0,返回res2: String = Hi, 2
自动补全:在scala>命令行内,可以使用Tab键进行自动补全。
二、声明变量
声明val常量:可以声明val常量来存放表达式的计算结果。
例如,val result = 1 + 1
但是常量声明后,是无法改变它的值的,否则会返回error: reassignment
to val的错误信息。
声明var变量:如果要声明值可以改变的引用,可以使用var变量。
例如,var myresult = 1,myresult = 2
但是在Scala程序中,通常建议使用val,也就是常量。
因为在Spark的大型复杂系统中,需要大量的网络传输数据,
如果使用var,值可能被错误的更改,所以建议多使用val。
三、数据类型与操作符
1》基本数据类型: Byte、 Char、 Short、 Int、 Long、 Float、 Double、 Boolean。
Scala的数据类型统一都是类。 Scala自己会负责基本数据类型和引用类型的转换操作。
使用以上类型, 直接就可以调用大量的函数, 例如, 1.toString(), 1.to(10)。
类型的加强版类型: Scala使用很多加强类给数据类型增加了上百种增强的功能或函数。
·例如, String类通过StringOps类增强了大量的函数, "Hello".intersect(" World")。
·例如, Scala还提供了RichInt、 RichDouble、 RichChar等类型, RichInt就提供了to函数, 1.to(10), 此处Int先隐式转换为RichInt,然后再调用其to函数。
2》基本操作符: Scala的算术操作符与Java的算术操作符也没有什么区别, 比如+、 -、 *、 /、 %等, 以及&、 |、 ^、 >>、 <<等。
但是, 在Scala中, 这些操作符其实是数据类型的函数, 比如1 + 1, 可以写做1.+(1)
例如, 1.to(10), 又可以写做1 to 10
注:Scala中没有提供++、--操作符, 我们只能使用+和-, 比如counter = 1,counter++是错误的, 必须写做counter += 1
3》除了方法之外,Scala还提供函数
数学函数:sqrt() pow() min()
引入特定包时使用import 包名._;
import scala.math._ ,_是通配符,类似Java中的*
四、流程控制结构
1、if表达式的定义: 在Scala中, if表达式是有值的, 就是if或者else中最后一行语句返回的值。
例如, val age = 30; if (age > 18) 1 else 0
可以将if表达式赋予一个变量, 例如, val isAdult = if (age > 18) 1 else 0
另外一种写法, var isAdult = -1; if(age > 18) isAdult = 1 else isAdult = 0, 但是通常使用上一种写法
2、if表达式的类型推断: 由于if表达式是有值的, 而if和else子句的值类型可能不同, 此时if表达式的值是什么类型呢?
Scala会自动进行推断, 取两个类型的公共父类型Any。
例如, if(age > 18) 1 else 0, 表达式的类型是Int, 因为1和0都是Int
例如, if(age > 18) "adult" else 0, 此时if和else的值分别是String和Int, 则表达式的值是Any, Any是String和Int的公共父类型。
如果if后面没有跟else, 则默认else的值是Unit, 也用()表示, 类似于Java中的void或者null。
例如, val age = 12; if(age > 18) "adult"。 此时就相当于if(age > 18) "adult" else ()。
3、将if语句放在多行中: 默认情况下, REPL只能解释一行语句, 但是if表达式通常需要放在多行。
可以使用{}的方式, 比如以下方式, 或者使用:paste和ctrl+D的方式。
if(age > 18) { "adult"
} else if(age > 12) "teenager" else "children"
注:默认情况下, Scala不需要语句终结符, 默认将每一行作为一个语句
4、一行放多条语句: 如果一行要放多条语句, 则必须使用语句终结符
例如, 使用分号作为语句终结符, var a, b, c = 0; if(a < 10) { b = b + 1;c = c + 1 }
通常来说, 对于多行语句, 还是会使用花括号的方式
var a, b, c = 0;if(a < 10) {
b = b + 1;c = c + 1}
5、块表达式: 块表达式, 指的就是{}中的值, 其中可以包含多条语句, 最后一个语句的值就
是块表达式的返回值。
例如, var d = if(a < 10) { b = b + 1; c + 1 }
6、输入和输出
print和println: print打印时不会加换行符, 而println打印时会加一个换行符。
printf可以用于进行格式化,例如, printf("Hi, my name is %s, I'm %d years old .", "Leo", 30)
readLine: readLine允许我们从控制台读取用户输入的数据, 类似于Java中的System.in和Scanner的作用。
综合案例:使用paste和ctrl+D
val name = readLine("Welcome to Game House. Please tell me your name: ")
print("Thanks. Then please tell me your age: ")
val age = readInt()
if(age > 18) {
printf("Hi, %s, you are %d years old, so you are legel to come here!", name, age)
} else {
printf("Sorry, boy, %s, you are only %d years old. you are illegal to come here!",
name, age)
}
五、循环
1、Scala拥有与Java相同的while和do-while循环
但没有与for(初始化变量;判断条件;更新变量)循环直接对应的对构。
Scala中的for:for(i<-表达式),让变量i遍历<-右边表达式的所有值。
注意:
1、在for循环的变量之前并没有val或var的指定,该变量的类型是集合的元素类型。
2、循环变量的作用域一直持续到循环结束
3、to 和 until,两者得到都是集合,区别如下:
scala> 1 to 10 (包含10)
res8: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> 1 until 10 (不包含10)
res10: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)
4、循环的几种遍历方式
一、直接遍历------遍历字符串
二、求和---------1到8的和
三、以 变量<-表达式 的形式提供多个生成器,用分号将它们隔开(嵌套循环)
for(i<- 1 to 9;j<- 1 to i){
if(i==j) println(j+"*"+i+"="+j*i)
else print(j+"*"+i+"="+j*i+"\t")
}
四、在循环中使用变量
for(i<- 1 to 6;tem=2*i-1;j<- 1 to tem){
print("*");if(j==tem) {println()}}
五、守卫式,即在for循环中添加过滤条件if语句
for(i<- 1 to 3;j<- 1 to 3 if i!=j) print((10*i+j)+" ")
六、推导式
如果for循环的循环体以yield开始,则该循环会构造出一个集合,每次迭代生成集合中的一个值。
六、函数
1、函数的分类
单行函数:def sayHello(name: String) = print("Hello, " + name)
多行函数:如果函数体中有多行代码, 则可以使用代码块的方式包裹多行代码, 代码块中最后一行
的返回值就是整个函数的返回值。 与Java中不同, 不能使用return返回值。
比如如下的函数, 实现累加的功能:
def sum(n: Int) :Int= {
var sum = 0;
for(i <- 1 to n) sum += i
sum}
2、函数的定义与调用
在Scala中定义函数时, 需要定义函数的函数名、 参数、 函数体。
def sayHello(name: String, age: Int) = {
if (age > 18) { printf("hi %s, you are a big boy\n", name); age }
else { printf("hi %s, you are a little boy\n", name); age}}
调用:sayHello("leo", 30)
注:Scala要求必须给出所有参数的类型, 但是不一定给出函数返回值的类型。
只要右侧的函数体中不包含递归的语句, Scala就可以自己根据右侧的表达式推断出返回类型。
3、递归函数与返回类型
如果在函数体内递归调用函数自身, 则必须给出函数的返回类型。
例如, 实现经典的斐波那契数列:
def feibo(n:Int):Int={
if(n<=2) 1
else feibo(n-1)+feibo(n-2)}
例如如下阶乘:
4、参数
1》默认参数
在Scala中, 有时我们调用某些函数时, 不希望给出参数的具体值, 而希望使用参数自身默认的值, 此时就在定义函数时使用默认参数。
def sayHello(firstName: String, middleName: String = "William", lastName:
String = "Croft") = firstName + " " + middleName + " " + lastName
如果给出的参数不够, 则会从左往右依次应用参数。
Java与Scala实现默认参数的区别如下:
-----------------------------------------------------------------------------------
Java:
public void sayHello(String name, int age) {
if(name == null) {
name = "defaultName"
} if(age == 0) {
age = 18
}}
sayHello(null, 0)
-----------------------------------------------------------------------------------
Scala:
def sayHello(name: String, age: Int = 20) {
print("Hello, " + name + ", your age is " + age)}
sayHello("leo")
2》带名参数
在调用函数时, 也可以不按照函数定义的参数顺序来传递参数, 而是使用带名参数的方式来
传递。如:sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack")
还可以混合使用未命名参数和带名参数, 但是未命名参数必须排在带名参数前面。如下:
正确:sayHello("Mick", lastName = "Nina", middleName = "Jack")
错误:sayHello("Mick", firstName = "Nina", middleName = "Jack")
3》使用序列调用变长参数
在如果要将一个已有的序列直接调用变长参数函数, 是不对的。 比如val s = sum(1 to 5)。
此时需要使用Scala特殊的语法将参数定义为序列, 让Scala解释器能够识别。
这种语法非常有用!Spark的源码中大量地使用。
例如:val s = sum(1 to 5 : _*) 通过:_*转换成参数序列
案例: 使用递归函数实现累加,如下:
def sum2(nums: Int*): Int = {
if (nums.length == 0) 0
else nums.head + sum2(nums.tail: _*)
}
调用:sum2(1,2,3,4,5) 或是 sum2(1 to 5 :_*)
注:1、定义nums为一个变长参数,定义函数时用*,调用函数需要表示一个参数序列时用:_*
2、head 表示集合中的第一个元素,tail 表示集合中除了第一个元素外的其他元素
七、过程
定义:在Scala中, 定义函数时, 如果函数体直接包裹在了花括号里面, 而没有使用=连接,
则函数的返回值类型就是Unit, 这样的函数就被称之为过程。过程通常用于不需要返回值的函数。
过程还有一种写法, 就是将函数的返回值类型定义为Unit。比较如下:
def sayHello(name: String) = "Hello, " + name
def sayHello(name: String) { print("Hello, " + name); "Hello, " + name }
def sayHello(name: String): Unit = "Hello, " + name
八、lazy值
在Scala中, 提供了lazy值的特性, 也就是说, 如果将一个变量声明为lazy, 则只有在第一次使用
该变量时, 变量对应的表达式才会发生计算。这种特性对于特别耗时的计算操作特别有用, 比如打开文件进行IO, 进行网络IO等。
1、import scala.io.Source._
lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString
即使文件不存在, 也不会报错, 只有第一次使用变量时会报错, 证明了表达式计算的lazy特性
val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString 这句会报错
2、val lines=sc.textFile("file:///home/tg/datas/ws")
val rdd1=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
val rdd2=rdd1.collect
算子: flatMap() map() reduceByKey()转换类型的算子(transformation)
collect()行动类型的算子(action)
3、val rdd=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).map(m=>(m._2,m._1))
.sortByKey(true).map(m=>(m._2,m._1)).collect
注:转换类型的算子就是lazy类型,当遇到action行动类型的算子时,才会触发执行。
总结下划线的用法:
1、导包时,导入包中所有内容 import scala.io.Source._
2、将数列(集合)转换成参数序列 val result=sum(1 to 10:_*)
3、表示Spark算子操作的每一个元素 lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
八、异常
在Scala中, 异常处理和捕获机制与Java是非常相似的。
try {
throw new IllegalArgumentException("x should not be negative")
} catch {
case _:IllegalArgumentException => println("Illegal Argument!")
} finally {
print("release resources!")
}
try {
throw new IOException("user defined exception")
} catch {
case e1:IllegalArgumentException => println("illegal argument")
case e2:IOException => println("io exception")
}
九、数组
若数组长度固定使用Array,若数组长度不固定则使用ArrayBuffer
1、定长数组的两种创建方式
1》val nums=new Array[Int](10); //10个整数的数组 2》val array=Array("hello","jack")
省略关键字new创建数组的方式,实际上调用的是 Array.scala中的apply()方法。源码如下:
def apply[T: ClassTag](xs: T*): Array[T] = {
val array = new Array[T](xs.length)
var i = 0
for (x <- xs.iterator) {
array(i) = x;
i += 1 }
array}
2、变长数组:数组缓冲
注:scala.collection.mutable._ 可变 scala.collection.immutable._ 不可变
对于那种长度按需要变化的数组,Java有ArrayList,Scala有ArrayBuffer
变长数组ArrayBuffer使用时要导包 import scala.collection.mutable.ArrayBuffer
var arr1=ArrayBuffer[Int]()
变长数组操作:1、arr1+=1 2、arr1+=(2,5,6) 3、arr1 ++=Array(3,4)
4、arr1.trimEnd(5) 返回值为空,需再次调用arr1来查看删除后的数据
5、arr1.insert(1,3,4) 指定1的位置添加3,4元素
6、arr1.remove(3)
7、arr1.remove(3,2) 指定位置删除指定数量的元素
3、变长数组与定长数组之间的转换
变长数组→定长数组:.toArray (不改变原来的数组,系统会自动创建一个新的arry)
定长数组→变长数组:.toBuffer
4、遍历数组
until是RichInt类的方法, 返回所有小于( 不包括) 上限的数字。
5、数组常用算法
,除了sum求和,max最大值,min最小值以外还有如下:
6、数组的quickSort()快速排序方法scala.util.Sorting.quickSort(array)
十、高阶函数
filter :把一个函数作为参数的函数
for(i <- 0 until arr1.length if(arr1(i)%2==0)) print(arr1(i)+" ")
array.filter(m=>m%2==0) 这里的m可以省去简写成 array.filter(_%2==0)
m=>m%2==0 匿名函数 m=>{m%2==0}
算子: spark中的算子有一部分是和scala中的高阶函数是一致的,
但是有一部分是scala中没有的,比如reducekey
简写用下划线代替m: val rdd=lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_)
lines.flatMap(m=>m.split(" ")).map(word=>(word,1)).reduceByKey((x,y)=>x+y)
十一、映射(Map)
1、Scala映射就是键值对的集合Map。默认情况下,Scala中使用不可变的映射。
如果想使用可变集合Map,必须导入scala.collection.mutable.Map
不可变:
val map=Map("tom"->20,"jack"->23,"marray"->22)
val map2=Map(("tom",20),("jack",23),("marray",22))
可变:
val map3=scala.collection.mutable.Map(("tom",20),("jack",23),("marray",22))
val map4=new scala.collection.mutable.HashMap[String,Int]
映射这种数据结构是一种将键映射到值的函数。 区别在于通常的函数计算值, 而映射只是做查询。
2、获取映射中的值
注:1》如果映射并不包含请求中使用的键, 则会抛出异常。
2》要检查映射中是否有某个指定的键, 可以用contains方法。
3》getOrElse方法, 若包含相应的键, 就返回这个键所对应的值, 否则返加0。
4》映射.get(键)这样的调用返回一个Option对象, 要么是Some(键对应的值), 要么是None。
3、修改Map的元素
更新可变Map集合:
1》更新Map的元素 ages("Leo") = 31
2》增加多个元素 ages += ("Mike" -> 35, "Tom" -> 40)
3》 移除元素 ages -= "Mike"
更新不可变Map集合:
1》 添加不可变Map的元素, 产生一个新的集合Map, 原Map不变
val ages2 = ages + ("Mike" -> 36, "Tom" -> 40)
2》移除不可变Map的元素, 产生一个新的集合Map, 原Map不变
val ages3 = ages - "Tom"
4、遍历Map操作
//遍历map的entrySet for ((key, value) <- ages) println(key + " " + value)
// 遍历map的key for (key <- ages.keySet) println(key)
// 遍历map的value for (value <- ages.values) println(value)
// 生成新map, 反转key和value for ((key, value) <- ages) yield (value, key)
5、SortedMap和LinkedHashMap
// SortedMap可以自动对Map的key的排序
val ages = scala.collection.immutable.SortedMap("leo" -> 30, "alice" -> 15, "jen" -> 25)
// LinkedHashMap可以记住插入entry的顺序
val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
ages("leo") = 30
ages("alice") = 15
ages("jen") = 25
6、Java Map与Scala Map的隐式转换
import scala.collection.JavaConversions.mapAsScalaMap
val javaScores = new java.util.HashMap[String, Int]()
javaScores.put("Alice", 10)
javaScores.put("Bob", 3)
javaScores.put("Cindy",
val scalaScores: scala.collection.mutable.Map[String, Int] = javaScores
===========================================================
import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute._
val scalaAttrMap = Map(FAMILY -> "Serif", SIZE -> 12)
val font = new java.awt.Font(scalaAttrMap)
7、元组(tuple)
概念:元组是不同类型的值的聚集,对偶是元组的最简单形态,元组的索引从1开始,而不是0
Tuple拉链操作:
Tuple拉链操作指的就是zip操作,zip操作是Array类的方法, 用于将两个Array, 合并为一个Array
比如 Array(v1)和Array(v2), 使用zip操作合并后的格式为Array((v1,v2)),合并后的Array的元素类型为Tuple。例子如下:
val students = Array("Leo", "Jack", "Jen")
val scores = Array(80, 100, 90)
val studentScores = students.zip(scores)
for ((student, score) <- studentScores) println(student + " " + score)
注:如果Array的元素类型是Tuple, 调用Array的toMap方法, 可以将Array转换为Map
如,studentScores.toMap
相关推荐
Scala SDK,全称为Scala Software Development Kit,是用于开发Scala应用程序的核心工具集。Scala是一种多范式的编程语言,融合了面向对象和函数式编程的特点,它运行在Java虚拟机(JVM)上,能够充分利用Java生态...
Scala是一种强大的静态类型编程语言,它融合了面向对象和函数式编程的概念,旨在提供一种可扩展的、高效的编程环境。Scala这个名字是“Scalable Language”的缩写,它旨在克服Java的一些局限性,同时保留其平台兼容...
Scala3,也被称为Scala 3或Dotty,是Scala编程语言的一个重大更新,旨在提高其简洁性、可读性和类型安全性。Scala3的发布标志着该语言的进一步成熟,它引入了一系列改进,旨在解决早期版本中的一些痛点,同时保持对...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的概念。这个"scala2.12.1Windows镜像包"是为Windows操作系统设计的Scala编程环境的安装包,版本号为2.12.1。Scala 2.12.x系列是其重要的一个稳定...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性。这个"scala学习源代码"的压缩包文件很可能包含了用于教学或自我学习Scala编程的基础示例。让我们深入了解一下Scala语言的关键概念和特性。 ...
Scala 是一种多范式的编程语言,它融合了面向对象和函数式编程的特性。下面将详细解释题目中涉及的Scala知识点: 1. **var、val 和 def 的区别**: - `var` 定义可变变量,可以多次赋值。 - `val` 定义不可变变量...
Scala是一种强大的多范式编程语言,它结合了面向对象和函数式编程的特性。MyBatis则是一款流行的Java持久层框架,主要用于简化数据库操作。在本项目中,"scala + mybatis 数据库查询",我们将探讨如何将Scala与...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的概念。这个"scala-2.12.10.zip"文件是Scala编程语言的特定版本——2.12.10,专为Windows操作系统设计的安装包。Scala 2.12.x系列是该语言的一个...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性,使得它在处理并发和大数据分析方面表现出色。"Scala实战高清讲解"这本书是学习Scala的宝贵资源,尤其对于那些希望深入理解并提升Scala技能的...
Scala是一种强大的多范式编程语言,它融合了面向对象编程和函数式编程的概念,被广泛应用于大数据处理和分布式计算领域,特别是在Apache Spark等框架中。标题提到的"scala-2.12.14.zip&scala-2.12.11.tgz"是Scala的...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性。这个"scala-2.13.8 解压安装版"提供了一个无需安装过程的便捷方式来使用Scala开发环境。以下是关于Scala-2.13.8版本的一些关键知识点: 1. ...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的概念,设计目标是提供一种静态类型系统,能够防止程序在运行时出现错误。Scala-2.12.6.tgz是一个针对该语言的最新版本安装包,用于在各种操作系统...
从上述内容来看,《Programming in Scala.pdf》不仅是一本介绍Scala编程语言的书籍,更是一本为读者提供深入了解和应用Scala语言的实用工具。书籍中的内容覆盖了从基础知识到高级特性的多个层面,确保读者能够在掌握...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特点,广泛应用于大数据处理、分布式计算和Web开发等领域。Spark是一个基于Scala构建的大数据处理框架,它以其高效、易用和可扩展性而受到业界的...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性。Scala-2.11.7是该语言的一个特定版本,适用于Java虚拟机(JVM)。这个包是官方发布的,确保了其可靠性和兼容性。 在安装Scala-2.11.7时,...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性,被广泛应用于大数据处理、分布式计算和Web开发等领域。Spark是基于Scala构建的大数据处理框架,其高性能和易用性使得Scala在大数据领域备受...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的特性,被广泛应用于大数据处理领域,特别是与Apache Spark相结合时。本课件是针对Scala学习者精心准备的资源,旨在帮助你深入理解和掌握Scala的...
在这个"windows版scala-2.11.12.zip"压缩包中,包含的是Scala 2.11.12版本的Windows兼容安装文件,这是Scala的一个稳定版本,适用于开发人员在Windows操作系统上进行Scala编程。 Scala 2.11.x系列是Scala的一个主要...
Scala是一种强大的多范式编程语言,它融合了面向对象和函数式编程的概念,为开发者提供了丰富的工具集。这个"scala-2.12.13.tgz"文件是Scala编程语言的一个版本,针对Linux操作系统提供的安装包。tgz(tar.gz)格式...
在本文中,我们将深入探讨如何使用Scala API操作HBase数据库。HBase是一个分布式、面向列的NoSQL数据库,它构建于Hadoop之上,提供实时访问大量数据的能力。Scala是一种强大的函数式编程语言,与Java虚拟机(JVM)...