scala安装与scala编程基础1
一、scala概述
-
编程语言的开发范式
a. 面向过程
b. 面向对象
c. 函数式编程 -
函数式编程概述
函数式编程:
将所有复杂的问题的解决 拆分为若干函数的处理 每一个函数可以去实现一部分功能 利用很多次函数的处理 最终解决问题。
函数式编程相对于面向对象编程 更加的抽象,好处是:
1. 代码可以非常的简洁 2. 更多的采用常量而不是变量来解决问题 这样额外带来的好处 在线程并发时 可以减少甚至杜绝 多线程并发安全问题 特别适合于应用在处理高并发场景 分布式场景下的问题 3. 函数式编程并不是面向对象编程的发展,而是另外一种解决问题的思路,两者之间也并没有绝对 的好坏之分,在不同的场景中各有各的优缺点。
-
Scala概述
1. Scala是一种函数式编程的语言 同时具有面向对象编程的特点。 2. Scala是基于JVM运行的: scala 是完全兼容java的,其实scala就是在java语言的基础上增加了一层编码的 “壳” 让程序人员 可以通过函数式编程的方式来开发程序。 Scala程序编写出.scala文件,需要先编译为.class文件,最终在jvm中运行: .java --> .class --> 字节码 .scala --> .class --> 字节码 由于scala最终被编译为.class 所以其实本质上还是java 所以在scala中可以任意的调用java的api。
二、Scala安装配置和使用(Window下)
-
安装
1. 前提条件:安装jdk并配置JAVA_HOME环境变量 (使用jdk1.8) 2. 安装scalashell: 双击运行scala-2.11.7.msi按照提示安装 3. 配置环境变量 将scala安装目录下的bin目录配置到path环境变量中 4. 安装spark 将spark-2.0.1-bin-hadoop2.7.tgz解压,将解压路径下的bin目录配置到path环境变量中
-
测试
win+R,输入cmd,进入dos命令窗口,运行spark-shell,出现如下界面则安装成功,有其他的报错 不用管
-
使用idea创建Scala项目
1. 在idea中下载插件Scala,然后重启
2. 创建新的Scala项目
这样就创建了一个普通的Scala项目
更加详细的创建方法:https://blog.csdn.net/qq_35826412/article/details/82187881
三、Scala语法
-
常量和变量
变量:可以在程序执行过程中进行修改 常量:一旦被赋值就不能再进行更改了 在java中变量用的比常量要多的多 但是在scala中更多的应用也更应该主动去应用常量 声明变量要用var关键字 //1.变量声明 var str1:String = "abc"; var str2 = "def"; str2 = "xyz"; val关键字用来声明常量 //2.常量声明 val str3:String = "abc"; val str4 = "def"; //str4 = "xyz";//报错
-
基本的数据类型
a. 基本数据类型共有9种
Byte Short Int Long Float Double Char Boolean String 这9种基本数据类型除了String是属于java.lang包以外,其它八种都归属scala包下,在scala中, java.lang和scala包都会自动引入,所以在程序中不需要导入就可以直接使用以上9种基本数据类型。 以上9种基本数据类型的用法基本和java中一致。
b. 富包装器
针对于以上九种基本数据类型,scala还提供了它们的富包装器类型,这9种基本数据类型可以在必 要时自动的转换为其对应的富包装器类型,使用更多的属性和方法,这个过程就是自动的封箱拆箱 的过程。 scala.runtime.RichByte scala.runtime.RichShort scala.runtime.RichInt scala.runtime.RichLong scala.runtime.RichChar scala.runtime.RichString scala.runtime.RichFloat scala.runtime.RichDouble scala.runtime.RichBoolean 装箱就是 自动将基本数据类型转换为包装器类型;拆箱就是 自动将包装器类型转换为基本数据类型
-
操作符
Scala中没有真正意义上的操作符,操作符即方法,方法即操作符
a. 操作符即方法
scala中操作符 也可以像使用方法那样去使用 val num1 = 3 + 2 val num2 = 3.+(2) println(num1) println(num2) val num3 = 3 * 2; val num4 = 3.*(2); println(num3) println(num4)
b. 方法即操作符
scala中方法 也可以像使用操作符那样去使用 val str1 = "abcdefg"; val c1 = str1.charAt(2); val c2 = str1 charAt 2; println(c1) println(c2) val str2 = "abcdefghijklmn" val r1 = str2.substring(2, 5); val r2 = str2 substring (2,5) println(r1) println(r2) val str3 = "abcdefg"; val r3 = str3.toUpperCase(); val r4 = str3 toUpperCase; println(r3) println(r4)
c. scala中操作符(函数)的优先级
scala中的操作符(函数)是有优先级的区分的,优先级由操作符(函数)的首字符决定: * / % + - : = ! < > & ^ | 所有字母 所有赋值操作符 也就是说,多个操作符连续运算(函数连续执行)的过程中,优先级要由首字符来确定,优先级越 高,越要优先执行,优先级相同的情况下,再遵循由上到下 由左到右的顺序依次执行,如果有小括 号,则小括号内的内容优先级最高。 这样的一个优先级规则,解决了scala中四则运算顺序问题:
d. 特殊运算符 冒号 的用法
scala中以冒号结尾的方法是一种特殊的函数,不同于普通的函数由左操作数调用传入右操作数, 这种方法是右操作数调用传入左操作数。
e. 操作符类型
i. 中缀操作符 中缀操作符 指操作符在两个操作数之间。 3.+(2) 等同 3 + 2 ii. 后缀操作符 后缀操作符 指 操作符在唯一的操作数之后 str1 toUpperCase 等同 str1.toUpperCase(); iii. 前缀操作符 前缀操作符 指 操作符在唯一的操作数之前 前缀操作符只有四种 + - ! ~ 前缀操作符特殊的地方在于,转换为方法时,不能直接转,而要转换为 unary_符号 形式 val n1 = -3 等同 val n1 = 3.unary_- val n2 = +5 等同 val n2 = 5.unary_+
-
控制结构
scala中的内建控制结构其实并不算多 以够用为主 因为可以自建控制结构
a. if判断
scala中的if的用法基本和java中一致,不同之处在于,scala中的if可以带有返回值 val num = 99 val r1 = if(num<10){ "哈哈" }else if(num<100){ "呵呵" }else{ "嘻嘻" } println(r1)
b. while , do…while 循环
scala中的while 和 do..while的用法和java中基本一致。不可带有返回值。 var i = 0; var sum = 0; while(i <= 10){ sum += i; i += 1; } print(sum) while和do..while不可避免的会使用到外界变量,以及很有可能要用到产生额外影响的操作,破坏函 数的封闭的特性,所以scala中通常不建议使用while do..while实现循环。通常推荐 使用递归 来实现 循环。
d. for循环
//i. 增强for val l1 = List(1,3,5,7,9); for(n <- l1){ println(n) } //ii. 普通for for(i <- 1 to 10){ println("abc"+i) } //iii. 过滤for(可以在循环条件后面添加过滤条件) //案例:遍历0到100的偶数 for(i <- 0 to 100; if i % 2==0){ println(i) } //案例:遍历0到100的偶数 过滤出其中大于30小于80的数] for(i <- 0 to 100; if i % 2==0;if i>30;if i<80){ println(i) } //iv. 嵌套for //案例:实现九九乘法表 for(i <- 1 to 9){ for(j <- 1 to i){ print(j +" * "+ i +" = "+i*j +" ") } println() } for(i <- 1 to 9; j <- 1 to i){ print(j +" * "+ i +" = "+i*j +" ") } //v. 流间变量绑定 //--流间变量定义 for(i <- 1 to 9; j <- 1 to i;val str = "\r\n"){ print(j +" * "+ i +" = "+i*j + str) } for(i <- 1 to 9; j <- 1 to i;val str = if (i==j) "\r\n" else " "){ print(j +" * "+ i +" = "+i*j + str) } //vi. 制造新的集合 for循环默认的返回值类型是Unit,即不能带回返回值 但是可以通过yield关键字将每次循环的的最后一个表达式的值组成集合返回 //--yield关键字创建新集合 val r = for(i <- 1 to 9;j <- 1 to i) yield { j +" * "+ i +" = "+i*j } println(r)
e. try…catch…finally捕获异常
scala中继承了java的异常机制 提供了 程序中产生意外情况时 处理的机制抛出异常的过程和java中 基本一致通过throw关键字进行 throw xxxException()一旦抛出可以当场捕获处理或接着向上抛,捕 获异常是通过 try catch finally来实现的 try{ val i = 1/0; }catch{ case t: NullPointerException => println("空指针异常!") case t: IOException => println("IO异常!") case t: RuntimeException => println("其他运行时异常!") case t: Throwable => println("其他异常或错误!") }finally{ println("无论如何都执行 finally") } // try..catch..finally可以带有返回值 val r = try{ val i = 1/0; }catch{ case t: NullPointerException => "空指针异常!" case t: IOException => "IO异常!" case t: RuntimeException => "其他运行时异常!" case t: Throwable => "其他异常或错误!" }finally{ "无论如何都执行 finally" } println(r) try..catch..finally中,finally块中的返回值 不会改变 try或catch块中返回值的值,这点和java 中是不同的
f. match匹配
// 类似于java中的switch..case语法,可以实现 匹配操作 val str = "def" val r = str match { case "abc" => "哈哈哈" case "def" => "呵呵呵" case "ghi" => "嘻嘻嘻" case _ => "啦啦啦" } println(r)
g. continue和break
scala中没有continue和break,如果想要实现 类似continue和break的操作,只能通过布尔类型的变 量来控制循环条件 //案例:将0到100的奇数进行累加 但如果累加值超过了50,则不再进行累加,求最后的累加的值 var x = 0; var sum = 0; var flag = true; while(x < 100 && flag){ if(sum>50){ flag = false; } if(x % 2==0){ // }else{ sum += x; } x += 1; } print(sum) 这种方式 可以避免continue和break的使用,但是引入了外部布尔类型的变量,破坏了函数封闭的 特点同样不推荐.官方推荐的做法,是通过递归的方式来实现: def mx(i:Int,sum:Int):Int={ if(sum>50 || i >100) sum; else if(i % 2 ==0) mx(i+1,sum) else mx(i+1,sum+i) } val r = mx(0,0) println(r)
四、函数
-
函数的概念
函数是一段具有特定功能的代码的集合由函数修饰符 函数名 函数参数列表 函数返回值声明函 数体组成可以将一段代码组合成函数,在后续需要时调用函数,执行代码,实现相应功能
-
函数的定义 - 普通函数定义
格式:
[override][final][public/private/protected] def 函数名(参数列表):返回值声明 = {函数体} 通过def关键字声明一个函数 def前面可以通过private protected来控制其访问权限 没有public 不写默认就是public的也可跟 上override final等关键字修饰 def sum1(n1:Int,n2:Int):Int={ return n1 + n2; }
在函数体中return关键字在不造成歧义的情况下可以省略,如果省略,则函数会将最后一个表达式的值作为返回值返回
def sum1(n1:Int,n2:Int):Int={ n1 + n2; }
大部分的情况下,函数可以自动推断返回值的类型,所以返回值类型的声明可以省略
def sum1(n1:Int,n2:Int)={ n1 + n2; }
如果函数体只有一行内容,则包裹函数体的大括号可以省略
def sum1(n1:Int,n2:Int)= n1 + n2;
如果返回值的类型是Unit,则 :Unit= 可以省略
def sum1(n1:Int,n2:Int){ println(n1 + n2) }
-
函数的定义 - 函数直接量定义
格式:(参数列表) => {函数体} 可以直接使用函数直接量快速定义一个函数 (n1:Int,n2:Int)=>{n1 + n2} 如果函数体只有一行内容,则包裹函数体的大括号 可以省略 (n1:Int,n2:Int)=>n1 + n2 如果函数的参数类型可以自动推断,则函数参数类型声明可以省略 (n1,n2)=>n1 + n2 //此处报错,并不是写法有问题,而是没有办法推断参数类型,所以报错 如果函数的参数列表中只有一个参数,则在不引起歧义的情况下,包裹参数类型声明的小括号可以省略 str:String=>str.toUpperCase()
-
函数的使用 - 成员方法
函数在scala中共有四种用法:成员方法 本地方法 函数值 高阶函数
scala中将函数作为类的一个成员,就称为函数称为了类的成员方法 /** * 函数功能1 : 作为类的成员方法使用 */ class Person{ private val name:String = ""; private val age:Int = 0; def say(){ println("说...") } def eat(food:String){ println("吃..."+food) } }
-
函数的使用 - 本地方法
函数在scala中共有四种用法:成员方法 本地方法 函数值 高阶函数scala中可以在函数内部再定义函数,这种用法称之为:函数用作本地方法 def eat(food:String){ def cook(food:String)={ "熟的"+food; } println("吃..."+cook(food)) }
-
函数的用法 - 函数值
函数在scala中共有四种用法:成员方法 本地方法 函数值 高阶函数函数本身可以理解为是一个对象,而函数名是指向这个对象的一个引用,所以可以将函数任意赋值给其他引用. def sum(n1:Int,n2:Int):Int={ return n1 + n2; } val sum2 = sum(_,_); val r = sum2(2,3) print(r) 也可以直接将一个函数直接量赋值给引用,从而通过引用调用该函数 val sum3 = (n1:Int,n2:Int)=>{n1+n2} val r = sum3(2,3) println(r)
ps:高级函数下次在说