Scala语言基础整合

Scala目录

Scala数据类型
java中有的scala数据类型

Byte 8bit的有符号数字,范围在-128 – 127
Short 16 bit有符号数字,范围在-32768 – 32767
Int 32 bit有符号数字,范围-2147483648到2147483647
Long 64 bit有符号数字,范围-9223372036854775808到9223372036854775807
Float 32 bit IEEE 754单精度浮点数
Double 64 bit IEEE 754双精度浮点数
Char 16 bit Unicode字符,范围U+ 0000到∪+FFFFString字符串
Boolean布尔类型
Null空值或者空引用

scala独有的数据类型
  • Unit表示无值,和其他语言中void等同(返回是空==返回式Unit)
  • Nothing所有其他类型的子类型,表示没有值(为防空指针出现,调用这个对象的某些方法不会报空指针)
  • Any所有类型的超类,任何实例都属于Any类型(等于Java里的Object),但是在scala中Object之下有Any(一人之下万人之上)
  • AnyRef所有引用类型的超类(引用类型:String)
  • AnyVal所有值类型的超类(值类型:Byte,Short,Int,Long)
变量和常量的声明
声明变量:var

变量是可以改变值的(安装scala的方法见前篇博文https://blog.csdn.net/Andrea_null/article/details/83420374)
也可以通过var声明多个对象[例: var heighat,score = 10]
在这里插入图片描述

声明常量:val

常量是不可以改变值的(如果改变,会报错如下error: reassignment to val意思是,不能给val重新赋值)
在这里插入图片描述

scala里面的入口函数

我们知道,在java中main函数当作入口函数,修饰它的为public static void。在scala中,入口的main函数也是静态的。但是在scala中没有static这一说,它使用的是Object块和class块来修饰。

凡是定义在Object块里面的属性(包括字段,方法)都是静态的

所以,Object块里要写main函数比如下方代码。
Object修饰Scala01就称之为Scala01的伴生对象。

凡是定义在class代码块里的都是非静态(动态)的

Class修饰Scala01就称之为Scala01的伴生类。
Class里面放实例化的属性

object Scala01 {     
  def main(args: Array[String]): Unit = {  }
  class Scala01{
}

伴生对象+伴生类==java中的某一个类
在scala中每行后面不需要加分号,直接通过换行来区分
但是一行中写了多个语句,语句与语句之间必须用分号来分割
例:var age = 18 ; var name = “angelababy”

创建类

在java里面,类名后面是不加小括号的,在Scala中,类名后面是可以加小括号的。
class Person(var id:Int, var name:String)代表了Person类的构造函数,这个构造函数有两个参数。
当参数用var修饰,那么可以直接通过对象来修改其值
当参数用val修饰,无法通过对象来修改值
当参数没有修饰,那么外部无法通过对象来调用。(没有修饰的话,这个参数是私有的)没有修饰的参数只能内部调用。

【注:可以理解成,使用var修饰,那么在它内部,给他自动生成来get和set方法。使用val修饰,只生成了set方法。如果没有修饰符,那么get和set都没有。只是举例子,不是真的生成】
在这里插入图片描述
代码中方法名是this的函数是这个类的构造器,以上Person类的默认构造器由两个参数xname和xage组成。this函数是重写的构造函数。重写的构造函数里要调用父构造函数。(重写的构造函数参数不能有修饰符,默认的可以加)

apply方法的使用

在这里插入图片描述
在加载scalaDemo1的时候,加载p对象调用的是Person类的构造方法,加载person对象的时候调用的是apply方法。apply方法在加载scalaDemo1的时候自动调用。类似于java的static{}。

注意点(类与对象)
  • 类和方法命名建议符合驼峰命名法。
  • scala 中的object是单例对象,相当于java中的工具类,可以看成是定义静态的方法的类。
  • object不可以传参数。另:Trait不可以传参数
  • scala中的class类默认可以传参数,默认的传参数就是默认的构造函数。
  • 重写构造函数的时候,必须要调用默认的构造函数。
  • class 类属性自带getter ,setter方法。
  • 使用object时,不用new,使用class时要new ,并且new的时候,class中除了方法不执行,其他都执行。(也可以用apply方法)
  • 如果在同一个文件中,object对象和class类的名称相同,则这个对象就是这个类的伴生对象,这个类就是这个对象的伴生类。可以互相访问私有变量。
判断语句
if else

在这里插入图片描述

if else if else

在这里插入图片描述

循环语句
for
通过索引
until:左闭右开

0.until(10,2)–>0到10,不包含10,步长是2

to:左闭右闭

在这里插入图片描述
每一次都把数给index,然后里面取list的值

增强for循环
 for(elem <- list){
      println(elem)
    }

上面elem为什么没有加类型?
因为scala有自动推测功能。由list类型推测出elem类型

循环练习1:打印99乘法表
 
    /**
     * 打印九九乘法表
     */
    for(i <- 1 to 9){
      for(j <- 1 until 10){
        if(j <= i){
          print(i + "*" + j + "=" + i*j + "\t")
        }
        if(j == i){
          println()
        }
      }
    }
循环练习2:寻找1-100之间的偶数(在for循环中可以加入判断条件)
  for(i <- 1 to 100;if i % 2 ==0) println(i)
  //也可以使步长是2直接输出
yield关键词案例:1-100集合中的偶数存储到另外一个集合中

Java风格传统写法:
在这里插入图片描述
Scala写法:

   val rest = for(i <- 1 to 10;if i % 2 ==0) yield i

yied关键词能够将符合要求的元素自动封装到一个集合中

while:前101次求婚

在这里插入图片描述
在scala中没有break跳出循环,如果想跳出循环,只能设一个flag作为标识符。

do…while:先执行循环体,再判断。

do…while循环先上船后补票的感觉
在这里插入图片描述

函数的定义(可以定义有参的,也可以定义无参的)

参数名在前,参数类型在后,并且中间要使用冒号
在这里插入图片描述

scala六种函数
普通函数

在这里插入图片描述

简写规则
  • 函数的返回值类型可以省略,因为scala具备自动推测功能,他会根据返回值自动决定这个函数的返回值类型。但是如果用return,需要加上返回值类型
  • 将要返回的值放在最后一行,那么这个值就会自动返回。
  • 如果函数体内只有一个语句,可以将这行语句与函数名在一行。
  • 如果匿名函数参数在函数体内只使用了一次,那么可以用下划线_代替
递归函数:函数体内调用自己本身[示例:计算number的阶乘]

5!=54321
在这里插入图片描述
递归函数必须加上返回值类型
自动推测返回值类型的时候,fun1(num-1)的返回值类型暂时未知。

包含参数默认值的函数:函数的参数有默认值

在调函数的时候可以传参,也可以不传参,若不传参,默认值会被覆盖
在这里插入图片描述
以上函数参数有两个默认值参数。
如果按照println(fun2(1,2))这样调取,输出的是3。
如果啥都不传println(fun2()),输出的是30 。
如果写成一个参数有默认值,一个参数没有默认值的函数如下:
在这里插入图片描述
调取的方法:
调取println(fun3(100))直接传给一个值就好,输出120 。
如果调用fun4并且希望第一个参数使用默认值,第二个参数使用传入的值
如果直接像fun3那样调取,报错not enough arguments
我们需要指定一下参数位置:println(fun4(num2=1000))这样调取就好了。输出1010 。

可变参数个数的函数:参数个数可以是一个,也可以是多个,随机灵活的

在这里插入图片描述
+=前后的数值类型必须一致
+前后数值类型可以不一致(出现自动类型转换)

如何调取?println(fun5(1,2))

匿名函数:没有名字的函数–重要
 var fun6 = (num1:Int,num2:Int) => num1+ num2

这个函数没名字,咋调用?
可以将这个函数赋给一个变量,在scala中他将函数也看成了一个对象,可以将函数赋给一个变量。
如果不赋给变量该怎么调?没法调。必须赋给变量。
注意点:

  • 1、匿名函数不能显示的声明返回值类型
  • 2、匿名函数必须赋给一个变量、变量,通过变量来调用这个匿名函数
  • 3、匿名函数的参数与函数体必须要用=>来关联
嵌套函数:在函数体内又定义了一个函数

在这里插入图片描述
在此处,fun7函数的体内又调用了fun8递归函数。

偏应用函数[示例:打印日志函数]

偏应用函数是一种表达式,不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
以打印日志的函数作为示例
在这里插入图片描述
参数前面是日志日期,后面是日志内容。
上图log函数的问题:调用三次log,它的Date都是相同的。所以不需要传。
logBoundDate底层调的也是log函数,把date写死,第二个参数以下划线表示String。
此时调用的时候只需要传字符串改变的值。
如果不提供参数:也行,把第二个参数也写死。但是不适用于生成日志的函数。

高阶函数:函数的参数是函数,或者函数的返回是函数
函数的参数是函数

在这里插入图片描述
f1参数是告诉我们要传入函数参数的格式。
此处把函数当成对象传递(scala支持面向函数编程)
如何将tmpFun当作参数调用?
highFun1(tmpFun,1000)
应该如上来调用,不能加小括号传参。
否则传入的参数就不是这个函数类型了,就是这个函数的返回值类型了。

函数的返回是函数

在这里插入图片描述
返回(Int,Int)=>Double这样格式的函数
上述两种函数进行了自动类型转换。
怎么调用?
调用方式1:调用这个函数,它给返回一个函数,再给返回的函数传入值。
eg:
val fun = highFun3()
println(fun(1,2))
调用方式2:匿名函数
eg:
highFun1((num:Int)=>num+1,1000)
此处,highFun1的参数需要一个函数,参数是Int类型,返回值也是Int类型,但是匿名函数不能明确给出返回值类型,只能通过最终的结果进行推测。
那么highFun3是highFun2利用匿名函数简洁了一下。
怎么调用?和上面一样,调用这个函数,它给返回一个函数,再给返回的函数传入值。

函数的参数是函数,函数的返回也是函数

在这里插入图片描述
此函数的参数是一个函数,返回也是一个函数
调用这个函数:

   val restFun = highFun4(_+_,1000)
   println(restFun(2000))
   println(highFun5(10)(20))

注:highFun5(10)返回一个函数,函数的参数是Int,所以又加了个小括号里面是20。运行结果是30 。

柯里化函数 :可以理解为高阶函数的简化

在这里插入图片描述
将两个参数分开来写。
调用方法: println(klhFun(100)(200))
对klhAllFun这种情况的高阶函数的简化版。

Scala字符串

在java中,字符串是由String来表示的,然而java里面的字符串是不可变的,如果想操作字符串,可以使用StringBuffer和StringBuilder。在scala里面也提供了这个类,同时scala也提供了java给提供的那些方法。

String
equals/equalsIgnoreCase/==

比较两个字符串对象的
值(区分大小写):用equals
值(不区分大小写):用equalsIgnoreCase
引用(地址):用==
在这里插入图片描述

split/substring

spilt:分词的方法,按照参数字符串进行分词,返回切割完成的String类型数组
substring:截取方法,给出截取的开始位置,截到最后。

 str1.split(" ")
compare/compareToIgnoreCase

如果参数字符串等于此字符串,则返回值 0;
如果此字符串小于字符串参数,则返回一个小于 0 的值;
如果此字符串大于字符串参数,则返回一个大于 0 的值。
compareToIgnoreCase是不区分大小写的比较

println(str.compareToIgnoreCase(str1))
hashcode

获取字符串的哈希值

StringBuilder

SringBuilder是一个可变长度的字符串。可以通过append方法往里面追加数据。如果想把它变成String字符串,要使用toString方法。在StringBuilder里也提供了split,compare等方法。
在这里插入图片描述
关于String的操作有更加详细的整理请参照我上传的资源。

数组
普通数组

java里面的数组创建形式:new String[10];
scala里面创建数组:使用Array关键字
如果创建了一个Int类型的数组,那么初始值都是0。
String类型的数组,初始是null
Boolean类型的数组,初始是false

//创建长度为10的Int类型的数组
val nums = new Array[Int](10)
//两种遍历数组的方法
for(index <- 0 until nums.length){
      nums(index) = index * index
    }
    //匿名函数参数类型可以自动推测
    nums.foreach {x => println(x)}
    //匿名函数的高级用法
    nums.foreach {println}

数组的其他方法:
clone克隆出一个新的数组
update更新数组
add往数组里添数据
addString往数组里加字符串
contains返回为真表示该数组里有参数这个值

关于数组中其他方法,参见我上传的资源。

二维数组

在这里插入图片描述
在scala里泛型是中括号。
二维数组,泛型里还是个数组。创建二维数组的时候需要一层一层的创建数组。
遍历数组的简便写法:

secArray.foreach { array => array.foreach { println } }
List集合:list集合是一个不可变的集合
contains方法:判断是否包含
drop方法:删除前(参数)个,返回一个新的,原来的不变
reverse方法:反转(生成新的,原来不变)
take方法:取前几个
val list = List(1,2,3,4,5)
    list.contains(6)
    val dropList = list.drop(2)
    dropList.foreach { println }
    list.reverse
    list.take(3).foreach(println)
    val mapList1 = list.map { x=> x +"" }
    mapList1.foreach { x=>println(x) }
    println(list.exists { x => x > 300 })
    println(list.mkString("\t"))
  }
map函数:高阶函数,参数是函数,这个函数的参数是int类型返回值是B(用户自定义类型)

List类型调用map,它的返回值是一个新的List

exits:是否存在,返回布尔类型

关于List的方法的总结请看我上传的资源
以下是关于Map函数的分词示例:

//分词
    val logList = List("hello bj","hello sh")
    val mapList = logList.map { _.split(" ") }
    mapList.foreach { x => x.foreach { println } }

以上方法打印出来的每一行都是一个数组,这个集合不是我们想要的。如何获得想要的集合?

flatMap方法 flat扁平 ,将集合压扁压平,数组里封装的元素跑到外面集合里面来了。

在map方法之上,加入扁平操作。

val flatMapList = logList.flatMap{_.split(" ")}
    flatMapList.foreach { println }

函数名后面有时加小括号,有时加大括号,都是一样的。
在这里插入图片描述

创建不可变的List集合的方式

方式1:List(1,2,3)
方式2:Nil关键词:表示空List
如何往这个空List里添加一条元素?
使用::形式

val list = 2::1::Nil
//表示list这个集合中添加了2和1这两条元素
可变的List集合:ListBuffer

依赖于包:scala.collection.mutable

new这个对象时,在代表泛型的中括号之后可以加小括号,也可以不加(不加代表调用无参的构造函数)

往ListBuffer中添加数据

方法1:使用addString方法
传入参数StringBuilder,返回StringBuilder
方法2:使用+=方法
在这里插入图片描述
在上图中,往这个ListBuffer中添加了两个元素。使用这个可变集合的主要目的就是为了方便添加元素。

注意:虽然不可变的List里也提供add方法,也可以加进去,但是加进去之后就不是原来的集合了而是产生一个新的集合,集合里的元素是加进去之后的元素。那么加入n个元素就会产生n多个对象,产生对象过多,容易内存溢出
拓展知识:研究垃圾回收(GC)机制

GC
Minor GC
Full GC

Minor GC主要是堆内存的年轻代满了,会清理年轻代的内存。
Full GC主要是堆内存的老年代满了。
GC部分知识后续会持续整理。

往ListBuffer中删除数据:使用-=

删除listBuffer中的hello元素

listBuffer.-=("hello")

关于listBuffer更详细的方法整合,参见我上传的list资源

Set集合:可以自动去重
创建Set的方式

去重测试:比如,创建set如下

val set = Set(1,1,2,3,2,5,6,7)
set.foreach{println}

当遍历的时候,会发现存入的是去重之后的数据(当然,它输出是无序的)
在这里插入图片描述

Set的其他方法
交集:intersect,&
   val set1 = Set(1,2,3,4)
   val set3 = set1.intersect(set2)
   set3.foreach{println}
   val set4 = set1.&(set2)
   set4.foreach{println}
   println("*******")
差集:diff,&~
  val set1 = Set(1,2,3,4,4)
  val set2 = Set(1,2,5)
  set1.diff(set2).foreach { println }
  set1.&~(set2).foreach { println }
子集:subsetOf
 set1.subsetOf(set2)
取最大值:max
 println(set1.max)
取最小值:min
 println(set1.min)
转成数组:toArray/toList
set1.toArray.foreach{println}
 set1.toList.foreach{println}
转成字符串:mkString("~")

集合所有元素作为字符串显示,参数为分隔符。

   println(set1.mkString)
   println(set1.mkString("\t"))
scala Set的其他方法

其他方法及其作用介绍已整理上传在博客资源。

Map集合
创建Map集合

形式1:Map(1 –>”bjsxt’)
形式2:Map((1,”bjsxt”))
注意:创建map时,相同的key被后面的相同的key顶替掉,只保留一个

 val map = Map(
      "1" -> "bjsxt",
      2 -> "shsxt",
      (3,"xasxt")
    )
遍历Map集合
方式1:

①获取Map集合的key:返回Interable集合类型

val keys = map.keys

②得到迭代器keyiterator

val keyiterator = keys.iterator

③通过循环来遍历迭代器

while(keyiterator.hasNext){
val key =keyiterator.next() 
println(key+"\t"+map.get(key).get)
}
Option
Some
None

注意:
Ⅰ这个循环里只能出现一次next(),否则会出现指向最后一个位置的时候,游标连跳两次,出现越界。
Ⅱmap.get(key)会返回一个Option对象。
get函数返回的是Option类型,Option类型有两个子类型,分别是Some类型和None类型。如果传入参数的key对应的键值对存在,那么返回的是Some对象。否则,返回None对象。
如果想拿到Some对象里面具体的值怎么拿?需要再.get一下。
如果是None对象,但是使用了.get方法强行取里面的值会发生什么?会报异常。异常是java.util.NoSuchElementException异常,表示没有匹配的元素。
为了避免这个异常,我们可以不使用get换成getOrElse
getOrElse:去集合中取数据,若不存在,返回默认值。

println(key+"\t"+map.get(4).getOrElse("default"))
方式2:for方式
for(k <- map)
println(k._1 + "\t" + k._2)

这里的k不是java中认为的Map中存放的Entry对象
而是二元组类型对象Tuple
一对小括号组成起来的形式就叫二元组

方式3:foreach方式

map本身封装了foreach方法,参数是一个函数

map.foreach(x=>println(x))//这里打印的是一个个二元组
map.foreach(x=>println(x._1 +"\t" +x._2))//分别把值取出来打印
合并Map:使用++

++ 使用方法:map1.++(map2) --map1中加入map2
使用举例:
在这里插入图片描述

Map的filter方法

在这里插入图片描述
留下符合要求的数据

Map的count方法

Map的count方法参数需要传入一个函数,函数返回值是布尔。意思就是,数一数满足传入函数中条件的元素一共有多少个
在这里插入图片描述

Map的contains方法

contains方法是找map中是否包含某个key

 println(map.contains(2))
Map的exist方法

exist方法是找符合条件的记录是否存在。
使用举例如下

 println(map.exists(f =>{
      f._2.equals("Angelababy")     
    }))

其他Map的方法总结已整理上传到本博客的资源。

Tuple元组
元组和list区别

List创建的时候指定了泛型,那么集合中必须是这个泛型的对象
元组中可以包含任意类型的元素,这些元素使用一对小括号来封装

创建元组
元组
二元组
三元组
...
/*创建二元组*/
//创建方式:
val t2 = Tuple2(1,"hello")
//简写创建方式:
val tt2 = (1,"hello")
/*创建三元组*/
//创建方式:
val t3 = Tuple3(1,true,"hello")
//简写创建方式:
val t3 = (1,true,"hello")

一般我们创建的时候不加Tuple2或者Tuple3等关键词
因为关键词的创建形式最大只可以创建22元组
直接用小括号的话可以创建很大很大的Tuple

取元组中的值

我们使用._的形式来取元组中的值
取x元组的第一个值那么就使用x._1形式获得。
例:如何取三元组t3的第二个值?

val t3value2 = t3._2
遍历元组

遍历元组的方式是使用迭代器遍历
Ⅰ利用.productIterator声明一个相应元组的迭代器
Ⅱ利用while方法遍历迭代器
Ⅲ用.next()取数据

val tupleIterator = tt3.productIterator
      while(tupleIterator.hasNext){
      println(tupleIterator.next())
    }
元组的方法
toString方法

示例:将元组tt3变成String格式

println(tt3.toString())

打印出来的结果是:(1,true,“hello”)
虽然看起来还是很像二元组,实际上它已经是字符串了。

swap交换方法

注意:只有二元组对象才会有这个方法
使用示例:

 println(tuple2)
 println(tuple2.swap)

输出之后发现后面的输出数据已发生反转。

trait

可以把trait理解为java里面的接口,但是它比java里的接口更加强大。

trait的特质

①可以实现方法
②可以定义任意的属性
举例1:trait中带属性带方法实现

继承的多个trait中如果有同名的方法和属性,必须要在类中使用“override”重新定义。
trait中不可以传参数

trait Read {
  val readType = "Read"
  val gender = "m"
  def read(name:String){
	println(name+" is reading")
  }
}

trait Listen {
  val listenType = "Listen"
  val gender = "m"
  def listen(name:String){
	println(name + " is listenning")
  }
}

class Person() extends Read with Listen{
  override val gender = "f"
}

object test {
  def main(args: Array[String]): Unit = {
    val person = new Person()
    person.read("zhangsan")
    person.listen("lisi")
    println(person.listenType)
    println(person.readType)
    println(person.gender)
    
  }
}

举例2:trait中带方法不实现

object Lesson_Trait2 {
  def main(args: Array[String]): Unit = {
    val p1 = new Point(1,2)
    val p2 = new Point(1,3)
    println(p1.isEqule(p2))
    println(p1.isNotEqule(p2))
  }
}

trait Equle{
  def isEqule(x:Any) :Boolean 
  def isNotEqule(x : Any)  = {
    !isEqule(x)
  }
}

class Point(x:Int, y:Int) extends Equle {
  val xx = x
  val yy = y

  def isEqule(p:Any) = {
    p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx
  }
  
}
模式匹配match

一个模式匹配包含了一系列备选项,每个都开始于关键字 case。
每个备选项都包含了一个模式及一到多个表达式。箭头符号 => 隔开了模式和表达式。

 /**
     * 模式匹配 match case
     * 		1、值
     * 		2、类型匹配
     * 在scala中模式匹配,一旦能匹配上第一个模式,那么接下来的模式都不会进行匹配了
     */
//模式匹配的时候,模式范围小的在最前面  
  def match_test(m:Any) = {
    m match {
      case 1 => println("first")
      case m:Int => println("Int")
      case _ => println("default")
    }
  }
样例类

样例类:使用case 来修饰的类就叫样例类
样例类和普通类有什么区别?
样例类默认帮你实现了toString,equals,copy和hashCode等方法。
样例类可以new, 也可以不用new
例:

   val s1 = Student(1,1)
     val s2 = Student(2,2)
     val s3 = Student(3,3)
     val s4 = Student(4,4)
     val s5 = Student(5,5)
     
     val sl = List(s1,s2,s3,s4,s5)
     //样例类+match case
     sl.foreach { x => x match {
       case Student(1,1) => println("1 1")
       case s:Student => println("Student" + s) 
       case _ => println("_______")
     } }
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值