Scala是一门多范式的编程语言,何谓多范式,就是多种方法编程。面向过程:类似c一个main函数顺序流执行;面向对象:java/c# oop;泛型,函数式等。
1,scala命令安装异常记录:
D:\source\scala-2.12.2\bin>scala
Exception in thread "main" java.lang.VerifyError: Uninitialized object exists o
backward branch 96
Exception Details:
Location:
scala/tools/nsc/CompilerCommand.sstring$1(Ljava/lang/String;Lscala/collecti
n/immutable/List;I)Lscala/Option; @153: goto
Reason:
Error exists in the bytecode
Bytecode:
0x0000000: 2bb6 02dc 9900 07b2 016a b0bb 0154 591c
0x0000010: ba02 e200 00b2 00c9 b600 cd3a 044e 1904
0x0000020: b200 c9b6 00d1 a600 7d2b b200 d6a6 000b
0x0000030: b200 d63a 09a7 0077 bb00 d859 2bb6 00db
0x0000040: c000 2b3a 0a1c 190a b802 deb2 00d6 b700
0x0000050: e83a 0519 053a 062b b600 ebc0 0050 3a07
0x0000060: 1907 b200 d6a5 0037 bb00 d859 1907 b600
0x0000070: dbc0 002b 3a0a 1c19 0ab8 02de b200 d6b7
0x0000080: 00e8 3a08 1906 1908 b600 ef19 083a 0619
0x0000090: 07b6 00eb c000 503a 07a7 ffc7 1905 3a09
0x00000a0: a700 0c2b 2d19 04b8 00f5 3a09 1909 c000
0x00000b0: 502a b602 e613 02e8 b602 e9b7 0159 b0
Stackmap Table:
same_frame(@11)
full_frame(@56,{Object[#118],Object[#80],Integer,Object[#333],Object[#335]}
{Uninitialized[#11],Uninitialized[#11]})
full_frame(@96,{Object[#118],Object[#80],Integer,Object[#333],Object[#335],
bject[#216],Object[#216],Object[#80],Top,Top,Object[#43]},{Uninitialized[#11],U
initialized[#11]})
full_frame(@156,{Object[#118],Object[#80],Integer,Object[#333],Object[#335]
Object[#216],Object[#216],Object[#80],Top,Top,Object[#43]},{Uninitialized[#11],
ninitialized[#11]})
full_frame(@163,{Object[#118],Object[#80],Integer,Object[#333],Object[#335]
,{Uninitialized[#11],Uninitialized[#11]})
full_frame(@172,{Object[#118],Object[#80],Integer,Object[#333],Object[#335]
Top,Top,Top,Top,Object[#4]},{Uninitialized[#11],Uninitialized[#11]})
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:41
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:104)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
原因系scala对jdk安装包要求,所以换旧版本scala解决
D:\ProgramFiles\scala\bin>scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_20).
Type in expressions for evaluation. Or try :help.
2,scala,eclipse插件安装:
解压下载的scala插件,在eclipse-install software中选中scala解压路径,逐步安装。
安装过程还会下载相关依赖包,网络不能断
3, scala的repl环境:
REPL — 交互式解释器环境。
R(read)、E(evaluate)、P(print)、L(loop)
可以在scala shell环境下执行外部scalc命令
当然,文件名也可以是Test.txt,只是一种加载外部命令的方式而已。
5,scala运行报错:
这是eclipse系统一个bug
scala和java的区别:
1,java和scala都从main函数开始:
scala代码
def main(args: Array[String]): Unit =
{
}
java代码
public static void main(String[] args)
{
}
2,查看scala安装包,可知scala依赖scalajar包,运行在jvm上,可以从交互,脚本的方式运行;
3,scala文件本身通过scalac生成java class类,写过测试类试试
object Test {
def main(args: Array[String]): Unit = {
print("aaa");
}
}
生成Test$.class和Test.class文件;
直接运行java Test报错,需要scala依赖,添加依赖以后
ok.为什么要用scala,因为scala和spark关系,更直接的说,spark由scala写,spark在大数据的优秀性能,所以用scala。估计是因为java本身的冗余问题比较多。
4,fold,左折叠和右折叠
var map1 = Map(1 -> "one", 2 -> "two", 3 -> "three", 4 -> "too")
println(map1)
var newDs = map1.map(_._2)
print(newDs)
运行结果:
Map(1 -> one, 2 -> two, 3 -> three, 4 -> too)
List(one, two, three, too)
json打印
println(compact(render(str)))
5,scala大小写敏感;
6,scala具有类型判断能力,行末的;是可选的:
java String 申明
String str = "aaa";
scala String 申明
val str = "aaa"
7,scala的基础数据类型:Byte,char,Short,Int,Long,Float,Bdouble,Boolean。
和java不同的是,scala的基础数据类型都是类,估计就是在java的基础上再封装一层;
8,操作符:
在Scala中,可以使用加(+)、减(-) 、乘(*) 、除(/) 、余数(%)等操作符,而且,这些操作符就是方法。例如,5 + 3和(5).+(3)是等价的,也就是说:
a 方法 b
等价于
a.方法(b)
前者是后者的简写形式,这里的+是方法名,是Int类中的一个方法。
val sum = 1+2
val sum = (1).+2
.+代表的是对象(1)执行的+方法
9,几个scala自定义的语法
to、until、by
10,import ×改为_
因为自动判断类型,所以import变得有点智能,
同样是定义map,在import可变map后, university就变成可变值了
11,scala返回值,
对于函数最后一个变量的值,即是返回值,所以看林子雨老师的教程中有写道
但是,有一点与Java不同的是,Scala中的if表达式的值可以赋值给变量,比如:
val x = 6
val a = if (x>0) 1 else -1
上述代码执行结束后,a的值为1。
原因是最后一个值是1,如果x值是-5,a的值就是-1;
不墨迹,直接验证下
12,生成器 <- 、守卫
for (变量<-表达式) 语句块
for (i <- 1 to 5) println(i)
在上面语句中,i不需要提前进行变量声明,可以在for语句括号中的表达式中直接使用。语句中,“<-”表示,之前的i要遍历后面1到5的所有值。
但是,有时候,我们可能不希望打印出所有的结果,我们可能希望过滤出一些满足制定条件的结果,这个时候,就需要使用到称为“守卫(guard)”的表达式。比如,我们只希望输出1到5之中的所有偶数,可以采用以下语句:
for (i <- 1 to 5 if i%2==0) println(i)
生成器多开
for (i <- 1 to 5; j <- 1 to 3) println(i*j)
运行上述代码后得到如下执行结果:
1
2
3
2
4
6
3
6
9
4
8
12
5
10
15
也可以给每个生成器都添加一个“守卫”,如下:
for (i <- 1 to 5 if i%2==0; j <- 1 to 3 if j!=i) println(i*j)
运行上述代码后得到如下执行结果:
2
6
4
8
12
13,数组引用,从【】转变为(),Martin Odersky真是好无聊
数组申明和定义
val myStrArr = new Array[String](3) //声明一个长度为3的字符串数组,每个数组元素初始化为null
myStrArr(0) = "BigData"
myStrArr(1) = "Hadoop"
myStrArr(2) = "Spark"
for (i <- 0 to 2) println(myStrArr(i))
val intValueArr = Array(12,45,33)
val myStrArr = Array("BigData","Hadoop","Spark")
列表申明和定义:
val intList = List(1,2,3)
val intList = 3::2::1::Nil
list方法:sum
14,元组tuple
这个数据结构定义的挺有意思,让不同数据类型元素排成队;
元组的蒂声明和访问
15,无参方法甚至连括号都可以省了
16,单例伴生对象:
/* 文件名:Marker.scala
* author:菜鸟教程
* url:www.runoob.com
*/
// 私有构造方法
class Marker private(val color:String) {
println("创建" + this)
override def toString(): String = "颜色标记:"+ color
}
// 伴生对象,与类共享名字,可以访问类的私有属性和方法
object Marker{
private val markers: Map[String, Marker] = Map(
"red" -> new Marker("red"),
"blue" -> new Marker("blue"),
"green" -> new Marker("green")
)
def apply(color:String) = {
if(markers.contains(color)) markers(color) else null
}
def getMarker(color:String) = {
if(markers.contains(color)) markers(color) else null
}
def main(args: Array[String]) {
println(Marker("red"))
// 单例函数调用,省略了.(点)符号
println(Marker getMarker "blue")
}
}
// 单例函数调用,省略了.(点)符号
println(Marker getMarker "blue")
编译后生成的Marker。class文件中,class Marker和 object Marker自动合成一个Marker class,
其中,class是动态方法和动态类;object是静态方法和静态类;
14.apply方法和update方法;
package com.yirong.basin.etl class TestApplyClassAndObject { } class ApplyTest{ def apply() = println("apply method in class is called!") def greetingOfClass: Unit ={ println("Greeting method in class is called.") } } object ApplyTest{ def apply() = { println("apply method in object is called") new ApplyTest() } } object TestApplyClassAndObject{ def main (args: Array[String]) { val a = ApplyTest() //这里没有用new,会调用伴生对象中的apply方法 a.greetingOfClass a() // 这里会调用伴生类中的apply方法 } }
result:
apply method in object is called
Greeting method in class is called.
apply method in class is called!
15,lamda表达式
s => s.toUpperCase
(参数) => 表达式 //如果参数只有一个,参数的圆括号可以省略
可以看出,Lamda表达式实际上是一种匿名函数,大大简化代码编写工作。s => s.toUpperCase,它的含义是,对于输入s,都都执行s.toUpperCase操作。
16,集合操作符
map/flatmap,reduce,
map操作是针对集合的典型变换操作,它将某个函数应用到集合中的每个元素,并产生一个结果集合。
比如,给定一个字符串列表,我们可以通过map操作对列表的中每个字符串进行变换,让每个字符串都变成大写字母,这样变换后就可以得到一个新的集合。下面我们在Scala命令解释器中,演示这个过程:
scala> val books = List("Hadoop", "Hive", "HDFS")
books: List[String] = List(Hadoop, Hive, HDFS)
scala> books.map(s => s.toUpperCase)
res0: List[String] = List(HADOOP, HIVE, HDFS)
flatMap是map的一种扩展。在flatMap中,我们会传入一个函数,该函数对每个输入都会返回一个集合(而不是一个元素),然后,flatMap把生成的多个集合“拍扁”成为一个集合。
scala> val books = List("Hadoop","Hive","HDFS")
books: List[String] = List(Hadoop, Hive, HDFS)
scala> books flatMap (s => s.toList)
res0: List[Char] = List(H, a, o, o, p, H, i, v, e, H, D, F, S)
reduce
在Scala中,我们可以使用reduce这种二元操作对集合中的元素进行归约。
reduce包含reduceLeft和reduceRight两种操作,前者从集合的头部开始操作,后者从集合的尾部开始操作。
fold和reduce类似,
折叠(fold)操作和reduce(归约)操作比较类似。fold操作需要从一个初始的“种子”值开始,并以该值作为上下文,处理集合中的每个元素。
从本质上说,fold函数将一种格式的输入数据转化成另外一种格式返回。fold, foldLeft和foldRight这三个函数除了有一点点不同外,做的事情差不多。我将在下文解释它们的共同点并解释它们的不同点。
我将从一个简单的例子开始,用fold计算一系列整型的和。
val numbers = List(5, 4, 8, 6, 2)
numbers.fold(0) { (z, i) =>
z + i
}
// result = 25
List中的fold方法需要输入两个参数:初始值以及一个函数。输入的函数也需要输入两个参数:累加值和当前item的索引。那么上面的代码片段发生了什么事?
代码开始运行的时候,初始值0作为第一个参数传进到fold函数中,list中的第一个item作为第二个参数传进fold函数中。
1、fold函数开始对传进的两个参数进行计算,在本例中,仅仅是做加法计算,然后返回计算的值;
2、Fold函数然后将上一步返回的值作为输入函数的第一个参数,并且把list中的下一个item作为第二个参数传进继续计算,同样返回计算的值;
3、第2步将重复计算,直到list中的所有元素都被遍历之后,返回最后的计算值,整个过程结束;
4、这虽然是一个简单的例子,让我们来看看一些比较有用的东西。早在后面将会介绍foldLeft函数,并解释它和fold之间的区别,目前,你只需要想象foldLeft函数和fold函数运行过程一样。
下面我们在Scala解释器中运行代码。
scala> val list = List(1,2,3,4,5) list: List[Int] = List(1, 2, 3, 4, 5) scala> list.fold(10)(_*_) res0: Int = 1200
可以看出,fold函数实现了对list中所有元素的累乘操作。fold函数需要两个参数,一个参数是初始种子值,这里是10,另一个参数是用于计算结果的累计函数,这里是累乘。执行list.fold(10)(*)时,首先把初始值拿去和list中的第一个值1做乘法操作,得到累乘值10,然后再拿这个累乘值10去和list中的第2个值2做乘法操作,得到累乘值20,依此类推,一直得到最终的累乘结果1200。
fold有两个变体:foldLeft()和foldRight(),其中,foldLeft(),第一个参数为累计值,集合遍历的方向是从左到右。foldRight(),第二个参数为累计值,集合遍历的方向是从右到左。对于fold()自身而言,遍历的顺序是未定义的,不过,一般都是从左到右遍历。
??
困扰了半天,终于明白了
对应的折叠符号
https://twitter.github.io/scala_school/zh_cn/collections.html#fold
8,本机spark安装:http://blog.csdn.net/u011513853/article/details/52865076
一定要在C盘运行该命令: F:\Program Files\hadoop\bin\winutils.exe chmod 777 /tmp/Hive
eclipse跑spark需要设置系统属性:
System.setProperty("hadoop.home.dir","D:/hadoop-2.6.4");
eclipse添加hadoop插件,下载地址
9,隐式转换
隐式转换函数是指在同一个作用域下面,一个给定输入类型并自动转换为指定返回类型的函数,这个函数和函数名字无关,和入参名字无关,只和入参类型以及返回类型有关。注意是同一个作用域。
- 记住隐式转换函数的同一个scop中不能存在参数和返回值完全相同的2个implicit函数。
- 隐式转换函数只在意 输入类型,返回类型。
/** * Created by skanda on 2017/8/21. */ object ImplicitDemo { def display(input:String):Unit = println(input) implicit def aaa(ccc:Int):String = ccc.toString implicit def aaa(ccc:Boolean):String = if(ccc) "true" else "false" // implicit def booleanTypeConvertor(input:Boolean):String = if(input) "true" else "false" def main(args: Array[String]): Unit = { display("1212") display(12) display(true) } }
10,模式匹配
11,json4s
12,开发过程出现的异常
12.1
正常的库没办法导入,库由pom.xml导入,怀疑是maven的问题,重新设置下maven即可
12.2,scala sdk设置
每次新建工程都要重复设置,在other setting里面设置default setting即可。
12.3,新建一个scala 测试类运行时总是显示 “无法加载的主类”
这个是因为类写在工程源码路径之外
推荐书籍:七天七语言
参考材料:厦大数据库实验室大数据教程