一、scala的数据类型
1,概述:
1)scala与java有着相同的数据类型,在scala中数据类型都是对象,也就是说是scala中没有java的原生类型 2)scala数据类型分为两大类AnyVal(值类型)和AnyRef(引用类型),注意:不管是AnyVal还是AnyRef都是对象。 3)相对于java的类型系统,scala要复杂些!也正是这复杂多变的类型系统才能让面向对象编程和函数式编程完美的融合在一起
2,数据类型体系一览图:
1)scala中有一个根类型Any,它是所有类型的父类 2)scala中一切皆对象,分为两类Anyval(值引用)和AnyRef(对象引用),它们都是Any子类 3)Null类型是scala的特别类型,它只有一个值null,它是bottom class是所有AnyRef类型的子类 4)Nothing类型也是bottom class,它是所有类的子类,在开发中通常可以将Nothing类型的值返回给任意变量或者函数,这里抛出异常使用很多
5)在scala中仍然遵守,低精度的值向高精度的值自动转换(implicit conversion)隐式转换。
3,Unit类型、Null类型和Nothing类型
1)Null类只有一个实例对象null,类似于Java中的null引用。null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal:比如Int,Float,Char,Boolean,Long,Double,Byte和Short) 2)Unit类型用来标识过程,也就是没有明确返回值的函数。由此可见,Unit类似于Java里的void。Unit只有一个实例{},这个实例也没有实质性的意义。 3)Nothing类型是Scala类层级的最低端,它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值时,可以用Nothing来指定返回类型,这样我们可以把返回的值(异常)赋给其他的函数或者变量
二、Scala的逻辑运算
1,if
if的逻辑运算与java基本类似,但是scala中if函数有返回值为(方法体的返回值)
2,for
0.until(10)等同于0 until 10 等同于Range(0,10) for(i<-0 until 10){ } 其中until为左闭右; to为左闭右闭
for循环中的break的使用
import scala.util.control.Breaks._ breakable{ for (i<- 0 to 10) { if (i==5){ break //break并非关键字而是Breaks中的break()方法,由于是无参函数可省略小括号直接调用 } println(s"${i}") } }
三、函数式编程
1,定义
def 函数名 ([参数名:参数类型],...)[[:返回值类型=]]{ 语句... return 返回值 }
a)函数声明关键字为def(definition)
b)[参数名:参数类型],... :表示函数的输入(就是参数列表),可以沒有。如果有,多个参数使用逗号隔开
c)函数中的语句:表示为了实现某一功能代码块
d)函数可以有返回值,也可以没有
形式1: :返回值类型= 形式2: = 表示返回值类型不确定,使用类型推导完成 形式3: 空 表示没有返回值,return不生效 等同于`:Unit=`
e)如果没有return,默认执行最后一行的结果为返回值
2,函数的参数和返回值
在scala中无论是值引用、对象引用还是函数都能作为函数的输入参数和返回值类型
a)函数作为参数
def f1(f: (Int) => Int) = { f(10) //调用传递进入的函数 } println(f1((i) => i + 10)) //将匿名函数(i) => i + 10作为参数 //println(f1(_ + 10)) //简化效果
b)函数作为返回值
def f3(a:Int) ={ println(a+10) } def f2() ={ f3 _ //返回函数f3不调用 } f2()(20) //函数的柯里化
c)函数的入参
//默认参数 def test(a:Int,b:Int=10) =a+b println(test(12)) //结果22,b的默认值为10 也可以指定为test(a=12)带名参数 //可变参 def test1(arr: Int*) = { var sum: Int = 0 for (i <- arr) { sum += i } sum } println(test1(1, 2,3)) //结果6
3,函数/方法注意事项和细节讨论
1)函数的形参列表可以是多个, 如果函数没有形参,调用时 可以不带() 2)形参列表和返回值列表的数据类型可以是值类型和引用类型。 3)Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,return关键字可以省略 4)因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略 5)如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成 : 返回类型 = ,当然如果你什么都不写,即使有return 返回值为() 6)如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值 7)如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any) 8)Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数/方法中可以再声明/定义函数/方法,类中可以再声明类 9)Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值 10)如果存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数11)scala 函数的形参默认是val的,因此不能在函数中进行修改. 12)递归函数未执行之前是无法推断出来结果类型,在使用时必须有明确的返回值类型 13)Scala函数支持可变参数
4,惰性函数
lazy val res = sum(1, 2) println("-----------------------") println("res=" + res) //当需要使用到res时,就会真正的开始计算 //将来这个计算方法是非常耗费运力 def sum(n1: Int, n2: Int): Int = { println("sum 被调用..") n1 + n2 }
1)lazy 不能修饰 var 类型的变量
2)不但是在调用函数时,加了lazy ,会导致函数的执行被推迟,我们在声明一个变量时,如果给声明了 lazy ,那么变量值得分配也会推迟。 比如 lazy val i = 10
5,异常
a)scala中的异常处理代码
//scala中去掉所谓的checked(编译) 异常 //设计者认为,如果程序员编程时,认为某段代码可疑,就直接try并处理 //说明 //1. 如果代码可疑,使用try进行处理 //2. 在catch中,可以有多个case ,对可能的异常进行匹配 //3. case ex: Exception => println("异常信息=" + ex.getMessage) // (1) case 是一个关键字 // (2) ex: Exception 异常的种类 // (3) => 表明后的代码是对异常进行处理,如果处理的代码有多条语句可以{}扩起 //4. 在scala中把范围小的异常放在后面,语法不会报错,但是不推荐 //5. 如果捕获异常,代码即使出现异常,程序也不会崩溃。 try { var res = 10 / 0 } catch { case ex: ArithmeticException => { println("算术异常=" + ex.getMessage) println("111") } case ex: Exception => println("异常信息=" + ex.getMessage) } finally { println("finaly的代码...") } println("程序继续....")
b)异常处理小结
1)我们将可疑代码封装在try块中。 在try块之后使用了一个catch处理程序来捕获异常。如果发生任何异常,catch处理程序将处理它,程序将不会异常终止。 2)Scala的异常的工作机制和Java一样,但是Scala没有“checked(编译期)”异常,即Scala没有编译异常这个概念,异常都是在运行的时候捕获处理。 3)用throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型。throw表达式是有类型的,就是Nothing,因为Nothing是所有类型的子类型,所以throw表达式可以用在需要类型的地方 def test(): Nothing = { throw new Exception("不对") } 4)在Scala里,借用了模式匹配的思想来做异常的匹配,因此,在catch的代码里,是一系列case子句来匹配异常。当匹配上后 => 有多条语句可以换行写,类似 java 的 switch case x: 代码块.. 5)异常捕捉的机制与其他语言中一样,如果有异常发生,catch子句是按次序捕捉的。因此,在catch子句中,越具体的异常越要靠前,越普遍的异常越靠后,如果把越普遍的异常写在前,把具体的异常写在后,在scala中也不会报错(不报错,但是不推荐),但这样是非常不好的编程风格。 6)finally子句用于执行不管是正常处理还是有异常发生时都需要执行的步骤,一般用于对象的清理工作,这点和Java一样。 7)Scala提供了throws关键字来声明异常。可以使用方法定义声明异常。它向调用者函数提供了此方法可能引发此异常的信息。 它有助于调用函数处理并将该代码包含在try-catch块中,以避免程序异常终止。在scala中,可以使用throws注释来声明异常 @throws(classOf[NumberFormatException])//等同于NumberFormatException.class def f11() = { "abc".toInt }