Scala Programming编程指南
汪文君
目录
写在最开始的话
其实在很久之前,我有自己学习过一些基于JVM的语言,包括Scala,Groovy,Bshell(不是linux中的shell,是最早的Sun公司出的bshell),但是在工作和日常生活中用不到之后,学习了又会忘记,不知道是不是记忆力不好的原因,但是此次公司决定使用Spark,准确的说是明年第二季度开始使用,所以我又开始整理关于Scala的知识,希望借着这个机会能够将Scala的语言特点整理,并且熟练掌握,应用于工作和日常开发之中。
关于Scala这门语言,其实语法量比Java多很多,很多老外建议我使用Clojure,不要使用Scala,他们给出最大的一个槽点就是语法太多,用他们的话讲就是完成一件事,scala有太多的方式可供选择,这样反倒不太好,但是不管怎样,既然要去使用这么语言来糊口养家,那么就自动屏蔽一些否定的声音,也许他们说的有道理。
另外一个很重要的话题是,如果你掌握了Java 8,其中一些函数式编程对知识,对学习Scala的帮助非常大,本人利用业余的时间录制了一套关于Java 8的视频教程,大概有40集,全部是针对Java 8新语法和新编程思想的实战,感兴趣的可以去下载观看
https://pan.baidu.com/s/1mhUYPK0
2、Scala复杂类型入门
2.1 Scala中的数组
在上一个电子书中,大致学习了一下如何定义变量,定义函数,以及使用scala脚本,简单介绍了一下while循环和foreach循环,我们在这一节课中我们来使用一些稍微复杂一点的Scala数据类型,就先从Array入手吧
2.1.1 Scala数组介绍
关于Scala中的数据其实和很多语言中的数据定义完全一样,说白了就是一个固定空间里存放着一些类型一样的数据,比如我们定义一个数组类型为String
val greetingString: Array[String] = new Array[String](3) |
当然其中的数据类型也是可以省略的
val greetingString = new Array[String](3) |
我们来看看如何给数组中的元素赋值以及获取元素的值
greetingString(0)="Hello" greetingString(1)="World" greetingString(2)="Scala" println (greetingString(0)) println (greetingString(1)) println (greetingString(2)) |
通过for循环的方式对其进行输出
for (i <- 0 to(greetingString.length - 1)) println(greetingString(i)) |
2.1.2 万物皆对象
上面的例子中,看到红色加粗的字体了么,写法有些奇怪,其实to是数字0的一个方法,数字也有方法?没错,在Scala中其实没有什么数字操作符可言,更没有Java中的所谓基本数据类型可言,所有的对象都是对象,0就是一个对象,+-/×这些都不是运算符,而是数字对象的方法,如果单纯这一点上来说,scala面向对象的更为彻底,那么我们再来看看既然是对象,为什么0后面没有对象导航符号“.”这是Scala的语言特性,在Scala中如果一个方法只有一个参数,所在对象对其的调用可以省略. 甚至参数的括号,我们来看看这个例子
object ArrayInAction { def main(args: Array[String]): Unit = { ArrayInAction.echo("Hello Scala") ArrayInAction echo "Hello Scala" } def echo(msg: String): Unit = { println(msg) } } |
2.1.3 再谈Array元素的存取
在2.2.1中我们看到,获取的方式是通过(),这一点和Java还是有区别的,这在Scala中其实也是一种简写的方法,是由Array的伴生对象提供的,我们来看看,完整的元素存取到底是怎么样的
val greetingString: Array[String] = new Array[String](3) greetingString.update(0, "Hello") greetingString.update(1, "World") greetingString.update(2, "Scala")
for (i <- 0 to (greetingString.length - 1)) println(greetingString.apply(i)) |
同步视频:
http://pan.baidu.com/share/link?shareid=2653942752&uk=1728517328&fid=1070408975120047
2.2 Scala中的List
和Array相比,List是可变长的,这是Java中的关于List的印象,可是在Scala中,List不仅不可变,里面的元素都不能变
2.2.1 List基本用法
val list1: List[Int] = List(1, 2, 3) |
我们定义了一个List,但是这个List不像我们想象的那样可变长,里面的元素是可以变化的,对其每一次的操作都会产生一个新的List
val list2: List[Int] = list1.updated(1, 100) |
改变了其中的一个元素,就会产生一个新的list
List之间的叠加:::,类似于addAll,但是仍然会产生一个新的List
val list3: List[Int] = List(1, 2, 3) val list4: List[Int] = List(4, 5, 6) val joinedList: List[Int] = list3 ::: list4 |
List append,有点类似我们给Java中的List add元素,但是他是右操作,看看下面的例子
val list5: List[Int] = 8 :: list3 |
根据我们前面的知识,是不是认为::是数字对象的方法呢?其实不然,这是List中的一个有操作符号,和下面的等价
val list6: List[Int] = list3.::(8) |
在List中还有一个非常重要对象Nil,他不等同于Lua语言中的nil,不代表NULL的意思,而代表一个空的List.
同步教学视频:
http://pan.baidu.com/share/link?shareid=2653942752&uk=1728517328&fid=615753914606763
2.2.2 List的更多用法
List提供的方法比较丰富,相对比Java中的list,方法比较多,我们在这里大概说一下其中的一些用法
上面的方法,我们不会一一介绍,简单的说几个就可以了
l Count
val count: Int = list.count(i => i > 4) |
统计符合条件的元素个数
l Drop
去掉List中前两位的元素
val list2 = list.drop(2) |
l dropRight
去掉最后面的两个元素
val list2 = list.dropRight(2) |
l Exists
List中是否存在一个特定的元素
val exists: Boolean = list.exists(i => i == 8) |
l Filter
获取符合条件的子集
val list2: List[Int] = list.filter(i => i % 2 == 0) |
l Forall
判断List中的所有元素是否满足条件
val forall: Boolean = list.forall(i => i > 2) |
l Map
对List中所有的元素都进行某种操作,产生一个新的,比如想让所有的元素都增大10倍
val map: List[Int] = l4.map(i => i * 10) |
2.2.3 同Java 8 的对比
关于List中的很多用法,其实用Java 8 Stream也可以实现类似的函数式效果,我们来看看如何使用Java 8 的stream结合lambda简洁有效的解决
package com.wangwenjun.chapter2;
import java.util.Arrays; import java.util.List; import java.util.Optional;
import static java.util.stream.Collectors.toList;
/*************************************** * @author:Alex Wang * @Date:2016/11/23 QQ:532500648 * QQ交流群:286081824 ***************************************/ public class ScalaListFunctionByJava { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 5, 6, 7);
long count = list.stream().filter(i -> i > 4).unordered().count(); Optional.of(count).ifPresent(System.out::println);
Optional.ofNullable(list.stream().map(i -> i * 10).collect(toList())) .ifPresent(System.out::println); } } |
本节同步视频地址:
http://pan.baidu.com/share/link?shareid=2653942752&uk=1728517328&fid=72806729262034
2.3 Scala中的Tuple
Tuple也是类似于List的容器,元组也是不可变的,但是它不同于List是因为它可以同时存放多类型的元素
package com.wangwenjun.chapter2
/** ************************************* * * @author:Alex Wang * @Date:2016 /11/26 * QQ:532500648 * QQ交流群:286081824 ***************************************/ object TupleInAction extends App {
val t1 = (123, 'X', "Hello"); println(t1._1) println(t1._2) println(t1._3) } |
我们简单定义了一个Tuple,分别存放了数字,字符,字符串类型,并且我们通过t1._1等方式对其进行了访问,在Tuple中没有apply方法,只能通过下标的方式来获取,那是因为,apply方法始终返回同类型的数据,但是很明显Tuple中的元素不具备这样的条件,更重要的一点是tuple中的元素下标开始是基于1而不是0.
2.4 Scala中的Set和Map
在Scala中也存在类似Java的Set和Map,但是他却有两种不同的实现,可变与不可变,基于入门的考虑,我们会在后面详细介绍Set和Map的用法,在这里只是暂时说说其基本用法
2.4.1 Scala中的Set
package com.wangwenjun.chapter2
/** ************************************* * * @author:Alex Wang * @Date:2016 /11/26 * QQ:532500648 * QQ交流群:286081824 ***************************************/ object SetInAction extends App {
var set: Set[String] = Set("Hello", "World") println(set) println(set hashCode) set.+=("Scala") set += "Scala" println(set) println(set hashCode) println("=========================") set.foreach(println) } |
Set中的元素是不可重复的,我们用默认的方式创建Set,产生的是一个不可变的Set,上面的这段代码只是简单的介绍了一下如何创建Set,如何给Set添加一个元素,关于更加深入的Set知识,我们在后面会详细说明
2.4.2 Scala中的Map
关于Map也是Key,Value的形式,在Scala中同样也有Map,只不过更加的丰富,同样,我们也会在后面专门的章节中详细介绍
package com.wangwenjun.chapter2
import scala.collection.mutable.Map
/** ************************************* * * @author:Alex Wang * @Date:2016 /11/26 * QQ:532500648 * QQ交流群:286081824 ***************************************/ object MapInAction extends App {
import scala.collection.mutable.Map
val map: Map[Int, String] = Map[Int, String](); map.+=(1 -> "Alex") map.+=(2 -> "WenJun") map.+=(3 -> "Scala") map.+=(4 -> "Java")
val map2: Map[Int, String] = Map( 1 -> "Alex", 2 -> "Scala", 3 -> "Java", 4 -> "Collection" )
map2.foreach(item => println(item._1 + "," + item._2+" "+item.getClass)) } |
2.5 函数式风格初识
我们还是拿循环输出作为函数式的演变,看看下面的代码
package com.wangwenjun.chapter2
/**************************************** * * @author:Alex Wang * @Date:2016 /11/26 * QQ:532500648 * QQ交流群:286081824 ***************************************/ object FunctionInAction {
def main(args: Array[String]): Unit = { val array: Array[String] = Array("Hello", "World", "Scala", "Java") printArray(array) printArrayForEach(array) printArrayFunction(array)
val map: Map[Int, String] = Map[Int, String]( 1 -> "Hello", 2 -> "World", 3 -> "Scala", 4 -> "Java" )
map.foreach(printMap) }
def printMap(item: Tuple2[Int,String]) = println(item._1 + " <=> " + item._2)
def printArray(array: Array[String]): Unit = { for (v <- array) println(v) }
def printArrayForEach(array: Array[String]): Unit = { array.foreach(println) }
def printArrayFunction(array: Array[String]) = array.foreach(println); }
|
上面的例子我们从printArray一直到printArrayFunction越来越函数化的演变,并且对Map的foreach进行了函数式的改进。
2.6 Scala和文件
在本小节中,我们简单的介绍一下Source类型,知道如何通过source获取文件的内容,关于更多文件操作的内容我们会在后面的章节中专门介绍
package com.wangwenjun.chapter2
package com.wangwenjun.chapter2
import java.io.File
import scala.io.Source
/** ************************************* * * @author:Alex Wang * @Date:2016 /11/26 * QQ:532500648 * QQ交流群:286081824 ***************************************/ object SourceInAction extends App {
val file: File = new File("C:\\Users\\wangwenjun\\IdeaProjects\\scalaInAction\\src\\com\\wangwenjun\\chapter2\\SourceInAction.scala");
val source: Source = Source.fromFile(file) val content: Iterator[String] = source.getLines for (line <- content) println(line) source.close() }
|
写在最后的话
本节课的内容大概就这么多,我们会逐步的更新,为了能够让读者尽快看到最新的内容,没更新一次就会发布一次,不用等到搞定一切之后再做统一发布,有问题可以和我交流,我们一起共同学习,共同进步,期待着你们的建议。
本篇文章的同步视频:http://pan.baidu.com/s/1qY5zjha