Scala

此篇文章正在更新ing,此篇文章适合有java语言基础或scala语言基础的朋友进行总结回顾。

第一章 入门

1、变量

scala声明变量应该显示地进行初始化

下面这是不被允许的

var name : String
name = "zhangsan"

声明和初始化要为一体的

如下可以默认进行初始化,默认初始化不能在方法中进行

var name : String = _

2、数据类型

1615550958967

只有有箭头指向的可以进行单方向【隐式转换】

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;
   }
}

说明:

  1. scala中的方法在编译时不会进行任何的改善

  2. 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、至简原则

  1. 函数体中如果返回最后一行代码的执行结果时,可以省略return
  2. 如果函数体只有一行逻辑的情况下,大括号可以省略
  3. 如果可以通过返回值推断出返回值类型的场合,返回值类型可以省略(多态除外)
  4. 如果参数列表中没有参数,那么可以省略参数列表的小括号
  5. return关键字和Unit语法有冲突,在同时存在时,return语句不起作用的
  6. 如果函数的名称没有那么重要的话,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. 函数不能先使用后声明的情况:
    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)
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值