Scala学习5
函数
java异常处理特点
Scala异常处理
Scala异常小结
惰性计算:尽可能延迟表达式求实,是许多函数是编程与语言的特性,惰性集合在需要时提供元素,无需预先计算。
java懒加载实现(懒汉式单例模式)
Scala原生支持实现惰性函数:返回值声明为lazy
def main(args: Array[String]): Unit = {
lazy val res = sum(1,3)
println("----------")
println("res = " + res)
}
def sum(n1:Int, n2:Int): Int = {
println("sum() 执行了")
n1 + n2
}复制注意事项
过程
将函数返回值类型为Unit的函数称之过程惰性函数
异常
Scala异常处理使用try...catch,语法与Java类似。
使用try...catch...catch...finally的方式来处理异常
不管有没有捕获异常,finally块都会执行,一般用于释放资源
Java将小范围异常写在前面,大范围异常写在后面,否则编译错误
在Scala中只有一个catch
在catch中有多个case,每个case可以匹配一种异常 case ex: ArithmeticException
=> 符号,表示后面对该异常的处理代码块
finally最终执行
def main(args: Array[String]): Unit = {
try {
val r = 10 /0
} catch {
case exception: ArithmeticException => {
println("捕获了除数为0的算数异常")
}
case exception: Exception => println("捕获了异常")
} finally {
println("scala finally...")
}
}复制
Scala异常的工作机制和Java一样,但Scala没有 "cheched(编译期)"异常,异常都在运行时捕获处理
throw关键字,抛出一个异常对象。所有异常都是Throwable的子类型,throw表达式的返回值是Nothing(所有类型的子类型)
def main(args: Array[String]): Unit = {
val res = test()
println(res.toString())
}
def test(): Nothing = {
throw new Exception("抛出异常")
}复制在Scala中,借用模式匹配的思想做异常匹配,所以,在Scala中使用一系列case子句来匹配异常
case子句按次序捕获异常,通常把小范围异常写在前,大范围写在后,当然,反过来写也不会报错。
Scala提供throw注解申明异常
@throws(classOf[NumberFormatException])
def f1() = {
"abc".toInt
}复制
lazy不能修饰var类型的变量
在调用函数时,加了lazy会导致函数执行被推迟,在声明变量时,如果声明lazy,变量值分配也会被推迟, lazy val i = 0
Scala面向对象
构造器属性
Bean属性 Scala字段加@BeanProperty时,会自动生成规范的getter/setter方法
object BeanDemo {
def main(args: Array[String]): Unit = {
val car = new Car
car.setName("hah")
car.getName
}
}
class Car{
@BeanProperty var name : String = _
}复制Scala构造器包含主构造器和辅助构造器
object ConDemo01 {
def main(args: Array[String]): Unit = {
val p1 = new Person("jack", 20)
println(p1)
}
}
/**
* 主构造器
* @param inName
* @param inAge
*/
class Person(inName: String, inAge: Int) {
var name: String = inName
var age: Int = inAge
age += 1
/**
* 辅助构造器
*
* @param name
*/
def this(name: String) {
this("hah", 20)
this.name = name
}
def this(age: Int){
this("jack",age)
this.age = age
}
println("执行~")
override def toString: String = {
this.name + " " + this.age
}
println(age)
}复制调用机制原理
注意
与Java一样
注意
Scala语言是面向对象的
Java是面向对象的语言(java 还存在非面向对象:基本类型,null,静态方法等),Scala源自Java,所以也是面向对象的,是纯粹的面向对象,int为Int面向对象方式
object CatDemo {
def main(args: Array[String]): Unit = {
val cat = new Cat
// public void name_$eq(String x$1) { this.name = x$1; }
cat.name = "小毕"
cat.age = 10
cat.color = "白色"
}
}
class Cat{
// 说明
// 1. 当我们声明了var name: String时,在底层对应生成 private name
// 2. 同时会生成两个public方法name() <=类似=> getter(), public name_$eq() => setter
/**
* public class Cat
* {
* private int age;
* private String color;
* private String name = ""; public String name() { return this.name; } public void name_$eq(String x$1) { this.name = x$1; }
* public int age() { return this.age; } public void age_$eq(int x$1) { this.age = x$1; }
* public String color() { return this.color; } public void color_$eq(String x$1) { this.color = x$1; }
* }
*/
var name: String = "" // 给初始值
var age: Int = _ // _表示给默认值0
var color:String = _ // _ 给默认值 ""
}复制定义类
属性
与Java一样,可以是值类型,也可以是引用类型创建对象
当创建的对象和new 对象有继承关系时,创建的对象必须写类型object CreateObj {
def main(args: Array[String]): Unit = {
val emp = new Emp
// emp2 必须写类型 Person
val emp2:Person = new Emp
}
}
class Person{
}
class Emp extends Person{
}复制类和对象的内存分配
与Java相同方法
构造器
属性高级
Scala对象创建流程
加载类的信息(属性,方法)
在内存(堆)开辟空间
使用父类构造器(主/辅助构造器)进行初始
使用主构造器对属性进行初始化
使用辅助构造器对属性进行初始化
开辟对象的地址赋给引用
Scala类的主构造器的形参未使用任何修饰符修饰,那么这个参数是局部变量
如果使用val关键字申明,那么Scala会将参数作为类的私有只读属性使用
如果使用var关键字申明,那么Scala会将参数作为成员属性,并提供对应的xxx()方法,即使这个属性是私有的,但也可以读写
辅助构造器函数名称为this,可以有多个,编译器通过不同的参数区分,底层就是Java构造器的重载, 辅助构造器必须第一行显示的调用主构造器
Scala构造器与Java一样,完成对新对象的初始值,构造器没有返回值
主构造器的申明在类名之后
主构造器会执行类定义中的所有语句
上面的代码反编译后如下
@ScalaSignature(bytes = "\006\001-3A!\004\b\0013!Aq\004\001B\001B\003%\001\005\003\005,\001\t\005\t\025!\003-\021\025y\003\001\"\0011\021\035)\004\0011A\005\002YBqa\016\001A\002\023\005\001\b\003\004?\001\001\006K\001\t\005\b\001\001\r\021\"\001A\021\035\t\005\0011A\005\002\tCa\001\022\001!B\023a\003\"B\030\001\t\003)\005\"B\030\001\t\0039\005\"B%\001\t\003R%A\002)feN|gN\003\002\020!\005Y1m\0348tiJ,8\r^8s\025\t\t\"#A\005dQ\006\004H/\032:1k)\0211\003F\001\006g\016\fG.\031\006\003+Y\taAY1z[VD(\"A\f\002\007\r|Wn\001\001\024\005\001Q\002CA\016\036\033\005a\"\"A\n\n\005ya\"AB!osJ+g-\001\004j]:\013W.\032\t\003C!r!A\t\024\021\005\rbR\"\001\023\013\005\025B\022A\002\037s_>$h(\003\002(9\0051\001K]3eK\032L!!\013\026\003\rM#(/\0338h\025\t9C$A\003j]\006;W\r\005\002\034[%\021a\006\b\002\004\023:$\030A\002\037j]&$h\bF\0022gQ\002\"A\r\001\016\0039AQaH\002A\002\001BQaK\002A\0021\nAA\\1nKV\t\001%\001\005oC6,w\fJ3r)\tID\b\005\002\034u%\0211\b\b\002\005+:LG\017C\004>\013\005\005\t\031\001\021\002\007a$\023'A\003oC6,\007%A\002bO\026,\022\001L\001\bC\036,w\fJ3r)\tI4\tC\004>\021\005\005\t\031\001\027\002\t\005<W\r\t\013\003c\031CQ!\016\006A\002\001\"\"!\r%\t\013}Z\001\031\001\027\002\021Q|7\013\036:j]\036$\022\001\t")
public class Person
{
private String name;
private int age;
public String name() { return this.name; } public void name_$eq(String x$1) { this.name = x$1; }
public int age() { return this.age; } public void age_$eq(int x$1) { this.age = x$1; }
public Person(String name) {
this("hah", 20);
name_$eq(name);
}
public Person(int age) {
this("jack", age);
age_$eq(age);
}
public String toString() { return true.toString(); }
public Person(String inName, int inAge) {
// Byte code:
// 0: aload_0
// 1: invokespecial <init> : ()V
// 4: aload_0
// 5: aload_1
// 6: putfield name : Ljava/lang/String;
// 9: aload_0
// 10: iload_2
// 11: putfield age : I
// 14: aload_0
// 15: aload_0
// 16: invokevirtual age : ()I
// 19: iconst_1
// 20: iadd
// 21: invokevirtual age_$eq : (I)V
// 24: getstatic scala/Predef$.MODULE$ : Lscala/Predef$;
// 27: ldc '执行'
// 29: invokevirtual println : (Ljava/lang/Object;)V
// 32: getstatic scala/Predef$.MODULE$ : Lscala/Predef$;
// 35: aload_0
// 36: invokevirtual age : ()I
// 39: invokestatic boxToInteger : (I)Ljava/lang/Integer;
// 42: invokevirtual println : (Ljava/lang/Object;)V
// 45: return
// Line number table:
// Java source line number -> byte code offset
// #46 -> 0
// #19 -> 4
// #20 -> 9
// #21 -> 14
// #38 -> 24
// #44 -> 32
// #18 -> 45
// Local variable table:
// start length slot name descriptor
// 0 46 0 this Lcom/baymux/scala/chapter05/constructor/Person;
// 0 46 1 inName Ljava/lang/String;
// 0 46 2 inAge I
}
}复制
当Scala开始执行时,现在栈区开辟一个main栈,main栈时最后被销毁的。
当Scala执行到一个方法时,总会开辟一个新的栈
每个栈时独立的空间,变量(基本数据类型)时独立的,相互不影响(引用类型除外)
当方法执行完毕后,该方法执行的栈就会被jvm回收
Scala申明的属性必须给初始值
如果赋值为null,必须给属性类型
var address = null // 引用时错误
复制如果定义属性时,不给默认值可以给_,系统会分配默认值
Scala中,类不能申明为public,所有这些类都具有公有可见性
一个Scala源文件可以包含多个类,默认都是public