1、Scala 简介算法
一、Scala语言既可用于大规模应用程序开发,也能够用于脚本编程,2001年由Martin Odersk 开发,主要优点 速度和它的表达性。一门函数式编程语言,既有面向对象的特色,又有面向过程的特色。编程
二、Scala与Java关系:Scala代码须要通过编译为字节码,而后交由Java虚拟机来运行,能够任意调用就Java的代码。因此Scala也就是JVM的一门编程语言。数组
三、安装Scala版本:scala-2.11.8msi; 进入cmd 下输入scala,进入Scala编程; scala -version 查看Scala版本网络
2、Scala基础编程语言
一、Scala解释器:进入安装Scala目录下——bin目录,运行scala.bat 函数式编程
scala解释器也被成为REPL(Read取值——Evalution求值——Print打印——Loop循环),会快速编译scala代码为字节码,而后交给JVM来执行。函数
在scala>命令行内,键入代码,解释器会直接返回结果,若是没有指定变量来存放这个值,那么值默认名称为res,并且会显示结果数据类型。oop
例:输入1+1,会看到res0:Int =2 spa
内置变量:在后面还能够继续使用res这变量,以及它存放的值 例:“hi,”+res0,返回res2:String =hi,2命令行
自动补全:在scala>命令行时,可使用Tab键进行自动补全
二、声明变量
声明常量: val result=1+1 声明后没法改变它的值 例:result=3(报错)
声明变量:var result=2,result=3 声明值能够改变引用 (建议使用val,在网络传输数据时,防止被错误的更改)
声明变量时,能够手动指定类型,也不能够不指定,scala会根据值进行类型推断,也能够将多个变量放在一块儿声明 例:val n1,n2 = 100 val na1,na2:String = null
三、数据类型与操做符
基本数据类型:Byte、 Char、 Short、 Int、 Long、 Float、 Double、 Boolean。 (与Java不一样的是首字母大写) scala数据类型统一都是类,scala本身负责基本数据类型与引用类型转换
使用以上类型, 直接就能够调用大量的函数, 例如, 1.toString(), 1.to(10) 结果是1到10 的一个集合
类型的增强版类型: Scala使用不少增强类给数据类型增长了上百种加强的功能或函数。
基本操做符: Scala的算术操做符与Java的算术操做符也没有什么区别, 好比+、 -、 *、 /、 %等, 以及&、 |、 ^、 >>、 <<等。
可是, 在Scala中, 这些操做符实际上是数据类型的函数, 好比1 + 1, 能够写作1.+(1)
例如, 1.to(10), 又能够写作1 to 10
Scala中没有提供++、 --操做符, 咱们只能使用+和-, 好比counter = 1, counter++是错误的, 必须写作counter += 1。
四、调用函数
除了方法以外,Scala还提供函数 ;import scala.math._ ,_是通配符,相似Java中的*
import scala.math._ sqrt(2)
3、控制结构、循环与函数
一、if表达式的定义: 在Scala中, if表达式是有值的, 就是if或者else中最后一行语句返回的值。
例如, val age = 30; if (age > 18) 1 else 0
能够将if表达式赋予一个变量, 例如, val isAdult = if (age > 18) 1 else 0
if表达式的类型推断: 因为if表达式是有值的, 而if和else子句的值类型可能不一样, 此时Scala会自动进行推断, 取两个类型的公共父类型。
例: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 ()
将if语句放在多行中: 默认状况下, REPL只能解释一行语句, 可是if表达式一般须要放在多行。 可使用{}的方式, 好比如下方式, 或者使用:paste和ctrl+D的方式。
例:
if(age > 18) { "adult" } else if(age > 12) "teenager" else "children"
二、语句终结符、块表达式
默认状况下, Scala不须要语句终结符, 默认将每一行做为一个语句
一行放多条语句: 若是一行要放多条语句, 则必须使用语句终结符 例如, 使用分号做为语句终结符, var a, b, c = 0; if(a < 10) { b = b + 1; c = c + 1 }
对于多行语句, 仍是会使用花括号的方式
块表达式: 块表达式, 指的就是{}中的值, 其中能够包含多条语句, 最后一个语句的值就 是块表达式的返回值。 例val d= if(a>10){"a";"b"} 返回的是b
三、输入输出
print和println: print打印时不会加换行符, 而println打印时会加一个换行符。
printf: printf能够用于进行格式化 例如, printf("Hi, my name is %s, I'm %d years old.\n", "Leo", 30)
readLine: readLine容许咱们从控制台读取用户输入的数据, 相似于Java 中的System.in和Scanner的做用。
输入输出案例:
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遍历<-右边表达式的全部值。
注意:在for循环的变量以前并无val或var的指定,该变量的类型是集合的 元素类型。 循环变量的做用域一直持续到循环结束。
(2)until方法返加一个不包含上限的区间 var sum =0;for(i<-0 until 10) sum+=i 区间是0到9,不包含10
直接遍历 val content="hello";for(c<- content) print(c+" ")
(3)能够变量<-表达式的形式提供多个生成器,用分号将它们隔开 例:for(i<-1 to 3;j<- 1 to 3)print((10*i+j)+" ")
for循环中添加过滤条件if语句,即为守卫式。 例:for(i<-1 to 3;j<- 1 to 3 if i !=j)print((10*i+j)+" ")
(4)在循环中使用变量 例:for(i<-1 to 3;from =4-i;j<-from to 3) print((10*i+j)+" ")
推导式:若是for循环的循环体以yield开始,则该循环会构造出一个 集合,每次迭代生成集合中的一个值。
例:for(i<- 1 to 10) yield i%3 生成Vector(1,2,0,1,2,0,1,2,0,1)
五、(1)高级for循环
多重for循环: 九九乘法表
for(i <- 1 to 9; j <- 1 to 9) { if(j == 9) { println(i * j) } else { print(i * j + " ") } }
if守卫: 取偶数 for(i <- 1 to 100 if i % 2 == 0) println(i)
for推导式: 构造集合 for(i <- 1 to 10) yield i
(2)在代码块中定义包含多行语句的函数体
单行函数:def a(name:String) =print("hello,"+name)
若是函数体中有多行代码, 则可使用代码块的方式包裹多行代码, 代码块中最后一行的 返回值就是整个函数的返回值。 与Java中不一样, 不是使用return返回值的。
def sum(n: Int) :Int= { var sum = 0 for(i <- 1 to n) sum += i sum }
:Int返回值的类型
(3)函数的定义与调用
在Scala中定义函数时, 须要定义函数的函数名、 参数、 函数体
Scala要求必须给出全部参数的类型, 可是不必定给出函数返回值的类型。 只要右侧的函数体中不包含递归的语句, 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 } s ayHello("leo", 30)
(4)递归函数与返回类型
若是在函数体内递归调用函数自身, 则必须给出函数的返回类型 。 例如实现经典的斐波那契数列: 9 + 8; 8 + 7 + 7 + 6; 7 + 6 + 6 + 5 + 6 + 5 + 5 + 4; ....
def fab(n: Int): Int = { if(n <= 2) 1 else fab(n - 1) + fab(n - 2) }
(5)默认参数
在Scala中, 有时咱们调用某些函数时, 不但愿给出参数的具体值, 而但愿使 用参数自身默认的值, 此时就定义在定义函数时使用默认参数。 若是给出的参数不够, 则会从左往右依次应用参数。
例:def sayHello(firstName: String, middleName: String = "William", lastName: String = "Croft") = firstName + " " + middleName + " " + lastName
(6)Java与Scala实现默认参数的区别
Java:
public void sayHello(String name, int age) { if(name == null) { name = "defaultName" } if (age == 0) { age = 18 } } s ayHello(null, 0)
scala:
def sayHello(name: String, age: Int = 20) { print("Hello, " + name + ", your age is " + age) } s ayHello("leo")
(7)带名参数
在调用函数时, 也能够不按照函数定义的参数顺序来传递参数, 而是使用带名参数的方式来 传递。
sayHello(firstName = "Mick", lastName = "Nina", middleName = "Jack")
还能够混合使用未命名参数和带名参数, 可是未命名参数必须排在带名参数前面。
sayHello("Mick", lastName = "Nina", middleName = "Jack")
(8)使用序列调用变长参数
在若是要将一个已有的序列直接调用变长参数函数, 是不对的。 好比val s = sum(1 to 5)。 此时须要使用Scala特殊的语法将参数定义为序列, 让Scala解释器可以识别。
val s = sum(1 to 5: _*) 经过 :_*转换成参数序列
例:使用递归函数实现累加
def sum2(nums: Int*): Int = { if (nums.length == 0) 0 else nums.head + sum2(nums.tail: _*) }
Int* :变长参数(参数长度可变) head取出集合第一个元素 tail 取出第一个剩下的元素
六、函数——过程、 lazy值和异常
过程:在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等。
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 与lazy val lines = fromFile("C://Users//Administrator//Desktop//test.txt").mkString的比较
lazy声明的这行代码并无被执行,当调用lines时才被执行,lazy是spark scala中很重要的特性
异常:在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") }
4、数组
一、数组
若长度固定使用Array,若长度不固定则使用ArrayBuffer
定长数组 val nums=new Array[Int](10); //10个整数的数组 或者 val str =Array("hello","world")
String 默认值是null Int默认值0 Boolean 默认值 是false ,取值时 数组用(),JAVA用[]
二、变长数组:数组缓冲
对于那种长度按须要变化的数组,Java有ArrayList,Scala有 ArrayBuffer
例:val arr=ArrayBuffer[Int]() 先导入包 scala.collection.mutable.ArrayBuffer
arr +=1 添加元素
arr++=Array(5,3,2) 添加元素
arr.trimEnd(5) 删除从后往前数5个
arr.insert(2,6) 第一个表明索引,剩下为添加的元素(在第三个数前添加6)
arr.remove(2,3) 第一个表明索引,第二个是个数(移除三个数,从第三个开始依次日后)
三、变长数组与定长数组之间的转换
变长数组→定长数组:.toArray 定长数组→变长数组:.toBuffer 对原数组没有影响,只是构建新的集合
四、遍历数组
for(i<-0 until arr.length) print(arr(i)+" ")
for(i<-(0 until arr.length).reverse) print(arr(i)+" ") 数组中的元素从后往前依次输出
for (i<-0 until (arr.length,2)) print(arr(i)+" ") 跳跃输出,长度为2,例:原数组 (1,2,3,4,5) 结果(1,3,5)
五、数组经常使用算法
arr.sum 求和 arr.max 求最大值 arr.min 最小值
val arrs=arr.sorted 对arr数组进行排序
val arrs=arr.sortWith(_>_) 降序排序
val arrs=arr.sortwith(_<_) 升序排序
arrs.mkString("and") arrs.mkString("&&") mkString方法容许指定元素之间的分隔符
5、补充
一、接口在scala中不存在, 函数存在不依赖类,方法依赖于类
二、实现直接三角形
for(i<-1 to 5;temp=2*i-1;j<-1 to temp){ print("*") if(j==temp)println() }
三、递归函数:自身调用自身
def fn(n:Int):Int{ if(n>0&&n<=1) 1 else n*fn(n-1) }
四、十进制转换成二进制
十进制6转换成二进制,6除以2等3余0 ,3除以2等1余1,1除以2等0余1,因此转换成二进制是 00000110 (总共8位,余数倒着来)
五、面向对象三大特性