此篇文章正在更新ing,此篇文章适合有java语言基础或scala语言基础的朋友进行总结回顾。
第一章 入门
1、变量
scala声明变量应该显示地进行初始化
下面这是不被允许的
var name : String
name = "zhangsan"
声明和初始化要为一体的
如下可以默认进行初始化,默认初始化不能在方法中进行
var name : String = _
2、数据类型
只有有箭头指向的可以进行单方向【隐式转换】
val a : Byte = 10
val b : Int = a
否则需要调用方法进行类型转换
Scala中AnyVal类和AnyRef类型两大分类没有直接的关系,所以不能互相转换
xx.toXxx //进行数据类型转换,也包括字符串和数字类型进行转换
3、字符串
3.1 传值字符串
printf("name=%s\n", name)
3.2 插值字符串
println(s"name=${name}")
3.3 多行字符串
println(s"""
| Hello
| ${name}
""".stripMargin)
4、IO
4.1输入
4.1.1控制台输入
val str: String = StdIn.readLine()
4.1.2从文件中读取输入
val source: BufferedSource = Source.fromFile("data/word.txt")
val strings: Iterator[String] = source.getLines()
while(strings.hasNext){
println(strings.next())
}
4.2输出
4.2.1输出到文件
val out = new PrintWriter("data/test.txt")
out.println("Hello Test")
out.println("Hello Zhangsan")
out.flush()
out.close()
4.3 网络
4.3.1客户端发送数据
//发送普通数据
val server = new Socket("localhost", 9999)
println("连接服务器成功,准备发送数据")
// 发送数据,采用输出流
val out: OutputStream = server.getOutputStream
out.write(300)
out.close()
println("数据发送成功")
server.close()
//发送对象
val server = new Socket("localhost", 9999)
println("连接服务器成功,准备发送数据")
// 发送数据,采用输出流
// 如果想要在网络中传递对象,需要将对象进行序列化,而且需要使用对象输出流
val out: OutputStream = server.getOutputStream
val objOut = new ObjectOutputStream(out)
val user = new User();
objOut.writeObject(user)
objOut.close()
println("对象数据发送成功")
server.close()
4.3.2服务端接收数据
//接收普通数据
val server = new ServerSocket(9999)
println("服务器启动成功,等待客户端的连接")
val client: Socket = server.accept()
println("客户端连接成功,等待客户端输入")
val in: InputStream = client.getInputStream
val i: Int = in.read()
println("接收到客户端的数据 :" + i)
in.close()
client.close()
server.close()
//接收对象
val server = new ServerSocket(9999)
println("服务器启动成功,等待客户端的连接")
val client: Socket = server.accept()
println("客户端连接成功,等待客户端输入")
// 从网络中获取对象,需要使用对象输入流
val in: InputStream = client.getInputStream
val inObj = new ObjectInputStream(in)
val user = inObj.readObject()
println("接收到客户端的数据 :" + user)
in.close()
client.close()
server.close()
5、运算符
5.1 ==
马丁 :双等号才会理解位真正的判断相不相等
判断对象相不相等时,判断内存地址的场景比较少,一般都是判断对象的属性(内容)是否相等
所以scala中马丁讲双等号的判断规则发生了改变: 双等号其实就是非空equals
val a:String=null
val b:String="aa"
println(a == b) //false
以上代码反编译成java
var10000;
boolean var10001;
label17: {
label16: {
String a = null;
String b = "aa";
var10000 = .MODULE$;
if (a == null) {
if (b == null) {
break label16;
}
} else if (a.equals(b)) {
break label16;
}
var10001 = false;
break label17;
}
var10001 = true;
}
var10000.println(BoxesRunTime.boxToBoolean(var10001));
val a:String=null
val b:String=null
println(a == b) //true
println( a eq b ) //true scala中的eq操作其实就是java中的 双等号
5.2 *
字符串的*号运算符表示字符串重复出现的次数
val a = "a" * 2
println(a)//aa
第二章 流程控制
1、三元运算符
val age = 30
var i = 0
if ( age > 20 ) i = 30 else i = 10
2、返回值
Scala中所有的表达式都有返回值,可以将返回值使用变量接收
这个返回值等于表达式满足条件的最后一行代码的执行结果
val i = 10
val res = if(i==10){
"10"
}else{
"20"
}
println(res)//10
3、for
3.1 标准for格式
for ( 元素名称:元素类型 <- 集合 ) {
循环体
}
3.2 range及实例
// 集合 (从 1 到(包含) 5)
val range1 = 1 to 5
// 集合 (从 1 直到(不包含) 5)
val range2 = 1 until 5
println(range1)//Range 1 to 5
println(range2)//Range 1 until 5
for ( num : Int <- range1 ) {
println(num) //1 2 3 4 5
}
println("*************************")
for ( num : Int <- range2 ) {
println(num) //1 2 3 4
}
println("*************************")
// 省略数据类型
for ( num <- range2 ) {
println(num) //1 2 3 4
}
val range3 = 1 to 5 by 2 //println+for: 1 3 5
val range4 = 1 until 5 by 2 //println+for: 1 3
val range5 = Range(1, 5, 2) // Range(start,end(不包含),step) println+for: 1 3
val range6 = Range(10, 1, -1)//println+for: 10 9 8 7 6 5 4 3 2
3.3循环守卫
循环时可以增加条件来决定是否继续循环体的执行,这里的判断条件我们称之为循环守卫
for ( i <- Range(1,5) if i != 3 ) {
println("i = " + i ) //1 2 4
}
//等价于
for ( i <- Range(1,5) ) {
if ( i != 3) {
println("i = " + i )
}
}
3.4引入变量
3.4.1嵌套循环
for ( i <- 1 to 3; j <- 1 to 3 ) {
println(s"i = ${i}; j = ${j}")//共9次循环
}
//相当于
for ( i <- 1 to 3 ) {
for ( j <- 1 to 3 ) {
println(s"i = ${i}; j = ${j}")
}
}
3.4.2循环变量
for ( i <- 1 to 3; j = i - 1 ) {
println(j)//0 1 2
}
//相当于
for ( i <- 1 to 3) {
val j = i - 1
println(j)
}
3.5表达式返回值
scala所有的表达式都是有返回值的。但是这里的返回值并不一定都是有值的哟。
如果希望for循环表达式的返回值有具体的值,需要使用关键字yield
val result = for ( i <- 1 to 3 ) yield {
i * 2
}
// 默认情况下,循环返回值为Unit
//println("result = " + result)
// 如果希望循环的每一个值都返回,需要采用特殊关键字
println("result = " + result)//result = Vector(2, 4, 6)
// TODO 线程的yield方法调用
Thread.`yield`()
4、break
Breaks.breakable {
for ( num <- 1 to 5 ) {
if ( num == 2 ) {
Breaks.break
}
println(num)
}
}
println("main...")
第三章 函数
1、函数的声明和使用
def main(args: Array[String]): Unit = {
// TODO 函数声明:
// def 函数名称( 参数名称1:参数类型1, 参数名称2:参数类型2 ) : 返回值类型 = { 函数体 }
def test() : Unit = {
println("test")
}
// TODO 函数调用
// 函数名称(参数1, 参数2)
test()
}
2、函数式编程
函数和方法的区别
java中方法表示功能的封装,但是强调这个功能属于谁
scala中函数表示代码(功能)的封装,但是不强调属于谁,只强调功能
scala中也有方法的封装,如何和函数进行区分:
在scala中,万物皆函数,所以方法也是函数,但是声明在了特殊的地方(类中)
所以调用方式也会有所区别
如果函数和方法声明相同,内部调用时,调用函数。
idea小图标:f => function
idea小图标:m => method
object scala04_function {
def main(args: Array[String]): Unit = {
//test("aa") //报错,因为当前环境中没有带String形参的方法,把下面的方法去掉即可
test() //function test... 编译器自行选择,优先选择函数,然后再选择方法
def test(): Unit = {
println("function test...")
}
}
def test(): Unit = {
println("method test...")
}
def test(name:String): Unit = {
println("method test...")
}
}
以上代码反编译
//decompiled from scala04_function.class
package com.ql.bigdata.fw_review.scala.chapter01;
import scala.reflect.ScalaSignature;
@ScalaSignature(
bytes = "\u0006\u0001e:QAB\u0004\t\u0002Q1QAF\u0004\t\u0002]AQ!H\u0001\u0005\u0002yAQaH\u0001\u0005\u0002\u0001BQ\u0001N\u0001\u0005\u0002UBQ\u0001N\u0001\u0005\u0002Y\n\u0001c]2bY\u0006\u0004Dg\u00184v]\u000e$\u0018n\u001c8\u000b\u0005!I\u0011!C2iCB$XM\u001d\u00192\u0015\tQ1\"A\u0003tG\u0006d\u0017M\u0003\u0002\r\u001b\u0005Iam^0sKZLWm\u001e\u0006\u0003\u001d=\tqAY5hI\u0006$\u0018M\u0003\u0002\u0011#\u0005\u0011\u0011\u000f\u001c\u0006\u0002%\u0005\u00191m\\7\u0004\u0001A\u0011Q#A\u0007\u0002\u000f\t\u00012oY1mCB\"tLZ;oGRLwN\\\n\u0003\u0003a\u0001\"!G\u000e\u000e\u0003iQ\u0011AC\u0005\u00039i\u0011a!\u00118z%\u00164\u0017A\u0002\u001fj]&$h\bF\u0001\u0015\u0003\u0011i\u0017-\u001b8\u0015\u0005\u0005\"\u0003CA\r#\u0013\t\u0019#D\u0001\u0003V]&$\b\"B\u0013\u0004\u0001\u00041\u0013\u0001B1sON\u00042!G\u0014*\u0013\tA#DA\u0003BeJ\f\u0017\u0010\u0005\u0002+c9\u00111f\f\t\u0003Yii\u0011!\f\u0006\u0003]M\ta\u0001\u0010:p_Rt\u0014B\u0001\u0019\u001b\u0003\u0019\u0001&/\u001a3fM&\u0011!g\r\u0002\u0007'R\u0014\u0018N\\4\u000b\u0005AR\u0012\u0001\u0002;fgR$\u0012!\t\u000b\u0003C]BQ\u0001O\u0003A\u0002%\nAA\\1nK\u0002"
)
public final class scala04_function {
public static void test(final String name) {
scala04_function$.MODULE$.test(var0);
}
public static void test() {
scala04_function$.MODULE$.test();
}
public static void main(final String[] args) {
scala04_function$.MODULE$.main(var0);
}
}
//decompiled from scala04_function$.class
package com.ql.bigdata.fw_review.scala.chapter01;
import scala.Predef.;
public final class scala04_function$ {
public static scala04_function$ MODULE$;
static {
new scala04_function$();
}
public void main(final String[] args) {
test$1();
}
public void test() {
.MODULE$.println("method test...");
}
public void test(final String name) {
.MODULE$.println("method test...");
}
private static final void test$1() {
.MODULE$.println("function test...");
}
private scala04_function$() {
MODULE$ = this;
}
}
说明:
-
scala中的方法在编译时不会进行任何的改善
-
scala中的函数在编译时会转换为方法
private static final void test$1() { .MODULE$.println("function test..."); }
private 私有的
static final : 不能被重写
test$1 : 名字发生了变化,为了避免重名
object scala04_function {
def main(args: Array[String]): Unit = {
test("aa")//正确
test()
}
def test(): Unit = {
println("method test...")
}
def test(name:String): Unit = {
println("method test...")
}
}
3、函数的输入与输出
3.1 方法/函数省略小括号
3.1.1 方法/函数无输入参数时
调用时,没有参数,直接使用小括号即可。如果没有参数,其实小括号可以省略。
object scala04_function {
def main(args: Array[String]): Unit = {
(new scala05_function).m1 //m1
f1 //f1
def f1(): Unit ={
println("f1")
}
}
}
class scala05_function{
def m1(): Unit ={
println("m1")
}
}
##############################################
object scala04_function {
def main(args: Array[String]): Unit = {
(new scala05_function).m1 //m1
f1 //f1
(new scala05_function).m1() //报错
f1() //报错
def f1: Unit ={
println("f1")
}
}
}
class scala05_function{
def m1: Unit ={
println("m1")
}
}
方法、函数定义时,若没有小括号,你调用也不能加小括号,否则会报错;方法、函数定义时,若加上小括号,你调用时小括号可加可不加例如,List 的size 方法没有括号,所以你必须写List(1,2,3).size。如果你尝试写List(1,2,3).size() 就会得到一个错误。如下代码,
println(List(1, 2, 3).size) //3
println(List(1, 2, 3).size()) //报错
3.1.2 方法/函数有输入参数时
当静态方法、方法只有一个参数时,可以省略点和小括号
当静态方法、方法有两个以上参数时,只能省略点
格式如下
对象 方法 参数1
对象 方法 (参数1,参数2...)
伴生类 静态方法 参数1
伴生类 静态方法 (参数1,参数2...)
object scala04_function {
def main(args: Array[String]): Unit = {
println((new scala05_function) m1 10) //10 m1
println((new scala05_function) m2 (10,"aa")) //10 aa m2
println((new scala05_function) m2 10 "aa")//报错
println(scala04_function f1 20) //20 f1
println(scala04_function f2(30, "aa")) //30 aa f2
println(scala04_function f2 30 "aa") //报错
}
def f1(id :Int) ={
println(id)
"f1"
}
def f2(id :Int,str:String) ={
println(id)
println(str)
"f2"
}
}
class scala05_function{
def m1(id :Int) ={
println(id)
"m1"
}
def m2(id :Int,str:String) ={
println(id)
println(str)
"m2"
}
}
4、函数参数的个数(最好不要超过22个)
函数定义时,若函数只是被调用,那么函数的参数不限个数
若将函数作为对象使用,参数的个数最大为22。
Scala中函数作为对象使用时,有专门的函数类型,这个函数类型最多只有22个参数,所以超过22个就没有对应的类型了。
def fun1(name1:String,name2:String,name3:String,name4:String,name5:String,name6:String,name7:String,name8:String,name9:String,name10:String,name11:String,name12:String,name13:String,name14:String,name15:String,name16:String,name17:String,name18:String,name19:String,name20:String,name21:String,name22:String,name23:String): Unit = {
println("25...")
}
//25...
fun1("1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "2")
val f : Function23 = fun1 _ //报错
val f = fun1 _
f //f 是nothing类型
5、可变参数
参数列表中没有声明参数时,调用可以省略小括号,可变参数可以不传参数,但是不是没有参数,所以必须使用小括号。
可变参数会转换为集合
fun("a","b") //WrappedArray(a, b)
def fun( name:String* ): Unit = {
println(name)
}
6、 默认参数(函数参数默认是val,带名参数)
函数的参数默认不可以修改的,等同于使用val修饰
Scala语言可以给函数的参数设定默认值,如果不传递参数,那么默认值会起作用
函数调用时,传值是和参数进行匹配,顺序匹配,类型匹配
如果想要改变参数的传值顺序,那么可以使用特殊语法:【带名参数】
def regUser( password:String = "000000", name:String ): Unit = {
println(s"注册用户 -》用户名:${name}, 密码:${password}")
}
regUser(null,"aa") // 注册用户 -》用户名:aa, 密码:null
//带名参数
regUser(name = "aa") //注册用户 -》用户名:aa, 密码:000000
7、至简原则
- 函数体中如果返回最后一行代码的执行结果时,可以省略return
- 如果函数体只有一行逻辑的情况下,大括号可以省略
- 如果可以通过返回值推断出返回值类型的场合,返回值类型可以省略(多态除外)
- 如果参数列表中没有参数,那么可以省略参数列表的小括号
- return关键字和Unit语法有冲突,在同时存在时,return语句不起作用的
- 如果函数的名称没有那么重要的话,def和函数名可以同时省略
// 1. 函数体中如果返回最后一行代码的执行结果时,可以省略return
def fun1(): String = {
//return "zhangsan"
"zhangsan"
}
// 2. 如果函数体只有一行逻辑的情况下,大括号可以省略
def fun2(): String = "zhangsan"
// 3. 如果可以通过返回值推断出返回值类型的场合,返回值类型可以省略(多态除外)
def fun3() = "zhangsan"
// 4. 如果参数列表中没有参数,那么可以省略参数列表的小括号
def fun4 = "lisi"
var fun44 = "wangwu"
// 如果参数列表被省略掉,那么为了统一语法,调用时也不能使用参数列表,不能加小括号
// 为什么scala中函数,变量声明时需要使用关键字
// 5. return关键字和Unit语法有冲突,在同时存在时,return语句不起作用的
// return在当前场合中,只是用于改变流程,而不会返回结果
// Unit想要省略的话,那么return就会起作用,就必须有返回值类型
// 又想return不起作用,又想省略Unit,那么可以省略Unit的同时将等号省略
def fun5(): Unit = {
return "zhangsan"
}
def fun55() : Unit = {
return "zhangsan"
}
def fun555() {
return "zhangsan"
}
// 6. 如果函数的名称没有那么重要的话,def和函数名可以同时省略
// 省略def和函数名时,应该同时省略返回值类型,需要依靠逻辑代码来推断返回值类型
// 在等号后面增加箭头(大于号)。明确函数体
// 参数列表 => 函数体
// 这种简化方式称之为【匿名函数】
def fun6(): Unit = {
println("fun6...")
}
// TODO 匿名函数
() => {
println("fun6...")
}
//val name = fun555()
//println(name)
8、将函数作为对象使用
声明函数时,等同于在声明对象。
如果想要使用函数对象,一般可以将函数对象赋值给变量,这个变量就等同于这个函数。
默认情况下,函数是调用,而不是当成对象。
如果想要让函数作为对象使用,而不是调用,需要采用特殊符号:【下划线】
函数类型:默认情况下,函数类型为FunctionX
这里的X表示参数个数,最多22个
函数类型还有其他声明方式 : In => Out
def main(args: Array[String]): Unit = {
def test(name:String): Unit = {
println("test..." + name)
}
val f : Function1[String, Unit] = test _
val f1 = test _
val f2 : (String)=>Unit = test
f("zhangsan")
f1("lisi")
f2("wangwu")
}
9、函数最好先声明后使用
-
函数能够先使用后声明的情况:
当做函数直接调用。
-
函数不能先使用后声明的情况:
1. 当做对象使用
2. 在直接调用函数和函数中间定义变量
函数能够先使用后声明的情况:
def main(args: Array[String]): Unit = {
test("直接调用")
def test(str:String): Unit = {
println("test..." + str)
}
}
函数不能先使用后声明的情况
def main(args: Array[String]): Unit = {
//1、当做对象使用
val testObj = test _
//2、在调用函数和函数中间定义变量
test("不能声明变量啊")
var a = 10
def test(str:String): Unit = {
println("test..." + str)
}
}