1、特性
统一类型

类型推断
可以使用 var 或 val 定义变量,编译器根据赋值自行推断变量数据类型。
var 用来声明变量,val 用来声明常量,类似 Java 中 final 修饰的变量。
var a = 1;
val b = "123";
// 可以指定类型
var c:Int = 1;
函数式
Scala 是函数式编程语言,因此所有方法都必须有返回值。Java 中 void 类型返回值,在 Scala 中使用 Uint 声明。
def tunit(i: Int): Unit = { }
主方法
主方法必须声明在 object 中。一个 Scala 文件种,可以声明多个 object 和 class,如果多个 object 中都具有 main 函数,则运行时需要指定启动 main 的 object 对象。
object Main {
def main(args: Array[String]): Unit = {
println("run")
}
}
CLASS & OBJECT
object 中声明成员成员和函数,类似于 Java 中 static 声明的静态成员和方法。
class 声明的对象,类似于 Java 中非静态成员和方法,必须通过 new 对象实例才可访问。
如果 object 和 class 同名,会产生伴生关系,伴生关系中 class 可以访问 object 中似有成员和函数。
裸露代码
object 中,在任何函数外的代码,类似于 Java 中 static { } 代码块中代码,会先于 main 函数执行。
object Main {
println("before main")
def main(args: Array[String]): Unit = {
println("main run")
}
println("after main")
}
// 输出顺序:
// before main
// after main
// main run
class 中,裸露代码,会被规整至类似于 Java 中无参构造函数中。
object Boot {
def main(args: Array[String]): Unit = {
new Boot boot()
}
}
class Boot {
println("before boot")
def boot(): Unit = {
println("boot run")
}
println("after boot")
}
// 输出顺序:
// before boot
// after boot
// boot run
类名构造器
类名构造器中参数,默认是 val 的常量,new 实例时必须赋值,也可以声明成 var 类型:class Boot(var sex: String) {}。
class Boot(sex: String) {
private var name: String = _
def this(sex: String, name: String) {
this(sex)
this.name = name
}
}
2、流控
IF 条件控制
var a = 22;
if (a <= 0) {
println("if branch")
} else if(a < 100) {
println("else if branch")
} else {
println("else branch")
}
WHILE LOOP
var w = 0;
while (w < 10) {
println(s"while loop -> $w")
// Scala 不允许使用 w++ 或 ++w 语法
w += 1;
}
RANGE
// 声明包含 1~10 的 Range 集合
var seqs: Range.Inclusive = 1 to 10
seqs.foreach(println)
// 通过步进为2 声明包含 1,3,5,7,9 的 Range 集合
var steps: Range.Inclusive = 1 to (10, 2)
steps.foreach(println)
// 声明包含 1~9 的 Range 集合
var untils = 1 to 10
untils.foreach(println)
FOR LOOP
var seqs = 0 to 10
for (i <- seqs) {
println(i)
}
// 循环逻辑 与 业务逻辑 分离
for (i <- seqs if (i % 2 == 0)) {
println(i)
}
嵌套循环
for (i <- 1 to 9) {
for (j <- 1 to i) {
print(s"${j}X${i}=${j * i}\t")
}
println()
}
// 可以简化为
for (i <- 1 to 9; j <- 1 to i) {
print(s"${j}X${i}=${j * i}\t")
if (j == i) println()
}
变量收集:使用 yield 关键字,代码块中最后一行数据,会被收集到结果集中。
var seq: IndexedSeq[Int] = for (i <- 1 to 10) yield {
print(s"$i ")
i * 2
}
println
println(seq)
// 输出
// 1 2 3 4 5 6 7 8 9 10
// Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
3、函数
返回值类型推断
- 不定义返回值类型,默认是
Unit类型。
def test() = { }
- 如果函数包含
return,则返回类型自动推断为return对象对应类型。
def test() = {
var a:Int = 3
var b:Int = a * 2
// b * 3 为返回值
// 因为没有显示声明 return 所以函数返回值类型启用类型推断
b * 3
}
- 如果声明了
return关键字,则函数必须声明返回值类型。
def test(): Int = {
return 1
}
参数
函数参数必须声明类型,且参数全部是 val 类型的,不可变更。
// Recursive 递归函数必须声明返回值类型
def func(num: Int): Int = {
if (num == 1)
num
else
num * func(num - 1)
}
函数赋值到变量
def func(): Unit = {
println("func invoke")
}
var method = func _
默认值函数
def main(args: Array[String]): Unit = {
func()
func(22)
func(name = "Arthur")
func(22, "Arthur")
}
def func(age: Int = 18, name: String = "Andy"): Unit = {
println(s"age: $age, name: $name")
}
可变参数
def func(a: Int*): Unit = {
println(s"length -> ${a.length}")
// 迭代遍历方式
a.foreach((x: Int) => { print(s"$x\t") })
a.foreach((x: Int) => print(s"$x\t"))
a.foreach(print(_))
a.foreach(print)
println
}
func()
func(1)
func(1, 2, 3, 4, 5)
匿名函数
def main(args: Array[String]): Unit = {
var func = (a: Int, b: Int) => {
a + b
}
println(func(3, 4))
var tfunc: (Int, Int) => Int = (a, b) => {
a + b
}
println(tfunc(3, 4))
}
嵌套函数
如果函数重名,则调用时优先寻找作用域最近的,且外部函数定义的变量对内部函数可见。
def main(args: Array[String]): Unit = {
var x = "x"
def tfunc: (String) => Unit = (a) => {
println(s"inner -> $a $x")
}
tfunc("arthur")
}
def tfunc(a: String): Unit = {
println(s"outer -> $a")
}
// 输出 inner -> arthur x
偏函数
var pfunc:PartialFunction[Any, String] = {
case "hello" => "value is hello"
case o: Int => s"value is int with $o"
case _ => "none"
}
println(pfunc("hello"))
println(pfunc(88))
println(pfunc("great"))
偏应用函数
var formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
def main(args: Array[String]): Unit = {
var info = log(_: Date, "info", _: String);
var debug = log(_: Date, "debug", _: String);
info(new Date, "ok")
debug(new Date, "debug log")
}
def log(date: Date, types: String, msg: String): Unit = {
println(s"${formatter.format(date)} - $types :> $msg")
}
高阶函数 - 函数作为参数
def compute(a: Int, b: Int, f: (Int, Int) => Int): Unit = {
var res: Int = f(a, b);
println(res);
}
compute(3, 8, (x: Int, y: Int) => x + y)
- 如果参数在匿名函数中,会顺序使用,且仅适用一次,可简化语法为
_+_。
compute(3, 8, _ + _)
compute(3, 8, _ * _)
高阶函数 - 函数作为返回值
def compute(a: Int, b: Int, i: String): Unit = {
var res: Int = factory(i)(a, b);
println(res);
}
def factory(i: String): (Int, Int) => Int = {
def add(x: Int, y: Int): Int = { x + y }
def sub(x: Int, y: Int): Int = { x - y }
if ("+".equals(i)) {
add
} else if ("-".equals(i)) {
sub
} else if ("*".equals(i)) {
(x: Int, y: Int) => { x * y }
} else if ("/".equals(i)) {
(x: Int, y: Int) => x / y
} else {
(x: Int, y: Int) => 0
}
}
compute(3, 8, "+")
compute(3, 8, "/")
柯里化
def currying(a:Int*)(b:String*): Unit = {
a.foreach(println)
b.foreach(println)
}
currying(1, 2, 3)("a", "b", "c")
4、集合容器
Scala mutable 包下是可变集合容器,immutable 包下是不可变集合容器。
数组
Scala 中,由于 [] 被泛型占用了,因此使用 () 定位数组下标。
val array = Array[Int](1, 2, 3, 4)
array(0) = 3
array.foreach(println)
List集合
- 不可变集合:
val list = List(1, 2, 3, 4, 5, 4, 3, 2, 1)
list.foreach(println)
- 可变集合:
val listbuf = ListBuffer[Int]()
listbuf.+=(1)
listbuf.+=(2)
listbuf.+=(3)
listbuf.foreach(println)
Set集合
- 不可变Set:
import scala.collection.immutable.Set
val set: Set[Int] = Set(1, 2, 3, 4, 3, 2, 1)
set.foreach(println)
- 可变Set:
import scala.collection.mutable.Set
val mutset = Set(1, 2, 3, 4)
mutset.add(8)
mutset.foreach(println)
Tuple
val tuple2 = new Tuple2[Int, String](11, "abc")
val tuple3 = Tuple3(11, "abc", 's')
val tuple4 = ((i: Int) => i + 8, 2, 3, 4, "aaa")
println(tuple2._2)
println(tuple4._4)
var x = tuple4._1(3)
println(x)
val tIter = tuple4.productIterator
while(tIter.hasNext) {
println(tIter.next())
}
Map
- 不可变Map:
import scala.collection.immutable.Map
var map: Map[String, Int] = Map(("a", 1), "b" -> 2, ("c", 3), ("a", 4))
val oa:Option[Int] = map.get("w").orElse(Some(0))
println(oa)
val ob = map.getOrElse("w", 0)
println(ob)
val keys:Iterable[String] = map.keys
for (key <- keys) {
println(s"key: ${key}, value: ${map.get(key).get}")
}
- 可变Map:
import scala.collection.mutable.Map
val map:Map[String, Int] = Map(("a", 1), ("b", 2))
map.put("c", 3)
map.remove("c")
符号方法
val list = List(1, 2, 3)
-
:::用于的是向队列头部追加数据,产生新的列表。
var nlist = 4 :: list
println(nlist)
// 输出: List(4, 1, 2, 3)
-
.:::与::作用相同。
var nlist = list.::(5)
println(nlist)
// 输出: List(5, 1, 2, 3)
-
:+:用于在队列尾部追加元素。
var nlist = list :+ 6
println(nlist)
// 输出: List(1, 2, 3, 6)
-
+:: 用于在队列头部添加元素。
val nlist = "A" +: "B" +: Nil
// Nil 是一个空的 List 定义为 List[Nothing]
println(nlist)
// 输出: List(A, B)
-
::::用于连接两个List类型的集合。
val list2 = List("A", "B")
var nlist = list ::: list2
println(nlist)
// 输出: List(1, 2, 3, A, B)
-
++:用于连接两个集合。
val list2 = List("A", "B")
var nlist = list ++ list2
println(nlist)
// 输出: List(1, 2, 3, A, B
5、Trait
object Main {
def main(args: Array[String]): Unit = {
var person = new Person("Andy")
person.hello()
person.say()
person.kill()
person.love()
person.pray("bless me")
var god:God = new Person("God")
god.pray("is god")
}
}
trait God {
def say(): Unit = {
println("god say")
}
def pray(info: String): Unit
}
trait Devil {
def kill(): Unit = {
println("devil kill")
}
}
trait Angel {
def love(): Unit = {
println("angel love")
}
}
class Person(name: String) extends God with Devil with Angel {
def hello(): Unit = {
println(s"${this.name} hello")
}
override def pray(info: String): Unit = {
println(s"god $info")
}
}
6、样例类
object Main {
def main(args: Array[String]): Unit = {
// 样例类不需要 new 关键字
var dog1 = Dog(3, "hsq");
var dog2 = Dog(3, "hsq");
println(dog1.equals(dog2))
// 输出 true
println(dog1 == dog2)
// 输出 true
}
}
case class Dog(age: Int, name: String) {
}
7、MATCH
val tuple: (Double, Int, String, Boolean, Char) = (1.0, 3, "ok", true, 'c')
val iter: Iterator[Any] = tuple.productIterator
val mapped = iter.map((x) => {
x match {
case 1 => s"$x is 1"
case 3 => s"$x is 3"
case true => s"$x is true"
case o: Char if o == 'c' => s"$o is Char with $x"
case _ => s"$x with default"
}
})
while (mapped.hasNext) println(mapped.next())
8、隐式转换
Scala 编译器发现 list.foreach(println) 找不到方法链接,则开始寻找 implicit 定义的参数类型与 list 一致的方法。
如果找到,则在编译器,将代码改写为 new EnhanceLinkedList[T](list).foreach(println)。
object Main {
def main(args: Array[String]): Unit = {
var list = new util.LinkedList[Integer]()
list.add(1)
list.add(2)
list.add(3)
implicit def enhance[T](list: util.LinkedList[T]): EnhanceLinkedList[T] = {
new EnhanceLinkedList[T](list)
}
list.foreach(println)
}
}
class EnhanceLinkedList[T](list: java.util.LinkedList[T]) {
def foreach(f: (T) => Unit): Unit = {
val iter = this.list.iterator()
while (iter.hasNext) f(iter.next())
}
}
也可通过隐式类定义,但隐式类必须为内部类。
import java.util
object Main {
def main(args: Array[String]): Unit = {
var list = new util.LinkedList[Integer]()
list.add(1)
list.add(2)
list.add(3)
list.foreach(println)
}
implicit class EnhanceLinkedList[T](list: util.LinkedList[T]) {
def foreach(f: (T) => Unit): Unit = {
val iter = this.list.iterator()
while (iter.hasNext) f(iter.next())
}
}
}
隐式参数
如果参数列表使用 implicit 修饰,则所有参数都需要在外部定义,才可使用隐式传参,且相同类型参数不可定义多个。
def main(args: Array[String]): Unit = {
implicit var name: String = "Andy"
implicit var age: Int = 18
def method(implicit name: String, age: Int): Unit = {
println(s"name: $name, age: $age")
}
method("Hudy", 22)
method
}
9、Spark
Word Counter
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Main {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setAppName("WordCount")
conf.setMaster("local")
val sc = new SparkContext(conf)
// val rdd: RDD[String] = sc.textFile("data/testdata.txt")
// val words: RDD[String] = rdd.flatMap((x: String) => { x.split(" ") })
// val pairwords: RDD[(String, Int)] = words.map((s: String) => (s, 1))
// val result: RDD[(String, Int)] = pairwords.reduceByKey(_ + _)
val result: RDD[(String, Int)] = sc.textFile("data/testdata.txt")
.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
result.foreach(println)
}
}