Kotlin 是一门现代但已成熟的编程语言,旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作,并提供了多种方式在多个平台间复用代码,以实现高效编程。Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。
Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。
在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。

1.内置数据类型

1.基本类型

String 字符串

Char 字符

Boolean 布尔

Int 整型

Double 浮点数

List 集合

Set 无重复的元素集合

Map 键值对的集合

fun main{
	var name:string = "Array"
}

val ===> 不可改变相当于js的readonly

fun main{
	var name:string = "Array"
}

const val====>编译时常量 修饰符const不能修饰局部

只能在函数之外定义

const val PI = 3.1415
fun main{
	var name:string = "Array"
}

2.数字类型

Byte

Short 短整型

Int 整型

Long 长整型 可以用_表示,计数 100_000_000

var n1:Long =10L
var n2:Long =100_000_000

UByte

UShort

UInt

ULong

无符号 在后面加上u或U和长整型类似

var n3:UInt = 123u
var n4:UInt = 123U
var n5:ULong = 123UL

Float

Double

默认为Double类型,如果要使用float要加上f或者F

var m1:Float = 1.12F
var m2:Double = 1.12
var m3:Float = 1.12f

3.Boolean类型

0,false,null为假,其他为真

&& || !

4.字符类型

使用.code获取ascII码

\u转义成字符(unicode编码)

val c1:Char = 'a'
println(c1.code)

val c2:Char ='\u2C77'
println(c2)

5.字符串

用三引号包括字符串=>原始字符串

.trimIndent()去掉空格

$变量名 格式化字符串

val s2:String = """
        aha
        sjs
        dld
        kjl
    """.trimIndent()
println(s2)
val s3:String = "$PI1 圆"
println(s3)
val s3:String = "${PI1} 圆" //可以用{}此时后面不用再加空格,{}里面也可以写表达式

6.运算符

与 and 或or 异或xor

shl 左移位 shr 右移位 ushr无符号右移位

2.条件语句

1.when 类似 switch

when (c) {
    1 -> {
        println("1")
    }

    2 -> {
        println("2")
    }

    3 -> {
        println("3")
    }

    else -> {
        println("0")
    }
}

2.for循环

..区间运算符20..100相当于 20 <= a <= 100

val Range1 = 5..10
val Range2 = 5..10
for (i in Range1 step 2){//一次+2
    println(i)
}
for (i in 10 DownTo 1){//从10到1
    println(i)
}

3.函数

函数可以嵌套使用即函数内部声明函数,在函数内部声明的函数只能在函数内部调用,并且可以使用嵌套该函数的函数体内的变量

fun main(){
    outer()
}

fun outer(){
    val value = 10
    fun inner(){
        println(value)
    }
    inner()
}

message:String指定形参类型

():unit指定返回值类型 unit相当于void即无返回值(可以省略不写)

fun test(message:String):Unit{
    println(message)
}

设置默认值

fun test1(a:Int=3,b:Int=6):Int{
    return a+b
}
//如果要指定第二个参数
test1(b=9)

简洁写法 返回值为a+b

fun test2(a:Int,b:Int) = a+b

引用函数

 fun main(){
	val test2 = ::test1
    test2()
}

fun test1(){
    println("hahha")
}

4.变量作用域

1.get set

var v:Int = 10
    get() = field * 100
    set(value) {
        println("赋值")
        field = 12
    }

fun main(){
    println(v)
}

5.常用库函数

var value1 = readln()

相当于Java的Scanner

//n次方
println(2.0.pow(4))
//绝对值
println(abs(value2))
//最小值
println(min(10,20))
//最大值
println(max(10,20))
//求根
println(sqrt(9.0))
//e
println(Math.E)
//pai
println(Math.PI)

println(sin(0.5*Math.PI))
println(cos(0.5*Math.PI))
println(tan(Math.PI))

println(asin(1.0));
println(acos(1.0));
println(atan(1.0));

5.函数类型变量

1.()->

1.()括号里为参数类型 ->后为返回值类型

fun main(){
    val fun1:(Int)->String = outer("Hello")
    val name = fun1(10)
    println(name)
}

fun outer(name:String):(Int)->String{
    //匿名函数
    return fun(number:Int):String{
        return number.toString()+"个"+name
    }
}

2.可以嵌套使用

fun fu1(n1:Int,n2:Int):((String)->String,String) -> String{
 
}

2.lamda表达式

//it代指第一个参数
val func1:(String)->Int = {
    println(it)
    10     //返回的值s
}
var func:(String,String)->Int = { a,b ->
    println(a)
    println(b)
    10
}
println(func("1","2"))

尾随lamda

fun main(){
    test{
        println(it)
        10
    }
}

fun test(func:(String)->Int){
    println(func("Hello"))
}

小实验

val v1 = fu1(10,20)
val f1 = v1("Hello"){
    "1"
}
println(f1)

fun fu1(n1:Int,n2:Int):(String,(String)->String) -> String{
    println(n1+n2)
    return fun(s2:String, fun2:(String)->String):String{
        return fun2("1234")+s2
    }
}

如果函数调用的是尾随的lamda则标签名字就是函数的名字

val fun2:(Int) -> Int = mytest@{
    if (it >10 ) return@mytest 10
    20
}

3.内联函数

1.声明内联函数

编译之后将函数原封不动加入到调用的位置

inline fun mytest() = { 
    println("1")
}

高阶函数使用lamda

内联高级函数的lamda参数可以直接写return不指定标签

fun main(){
	mytest {
        return //内联高级函数的lamda参数可以直接写return不指定标签
    }
    println("Hi")
}

inline fun mytest(func: (String) -> Int):Unit{
    println("1")
    func("2")
}

在不需要内联的函数形参上添加noinline关键字,可以防止函数调用内联

标签可以指定为外部的函数名称

6.类和对象

1.类的创建

var 可改

val 不可改

class Student constructor(var name:String,val age:Int){
    
}

如果在类中定义,要赋值

class Student {
    var name:String = "Jack"
    var age:Int = 18
}
class Student(name:String,age:Int) {
    var name:String = name
    var age:Int = age
}

懒加载,在使用之前必须初始化

class Teacher{
    lateinit var name: String
    lateinit var age:Integer
}

2.对象的创建

val s1 = Student("Jerry",44);
println(s1.age)
println(s1.name)

s1.name = "Tom"
println(s1.name)

constructor

当类有主构造函数是,其他次要构造函数都要调用主构造函数

主构造函数可以省略constructor不写

                //主构造函数
class Student1(var name:String,var age:Int){
    //次要构造函数
    constructor(name:String):this(name,90)
}
class Student1{
    constructor(name:String)
}

3.对象的初始化

在创建对象时会执行init里的代码

可以写多个init 相当于主构造函数的函数体

class Teacher1(var name:String,var age:Int){
    init {
        println("创建成功")
    }
}

4.基本数据类型常用方法

val v1:String = "10"
println(v1.toInt())
val v2:String = "samll"
println(v2.uppercase())
val v3:String = "BIG"
println(v3.lowercase())
val v4:String = "how are you"
println(v4.replace('o','m'))

//获取长度(字符串)
println(v4.length)

5.运算符重载

重载二元运算符 +

class Student constructor(var name:String,var age:Int){
    operator fun plus(another:Student):Student{
        return Student(this.name+another.name,another.age+this.age)
    }
}

重载一元运算符 !

operator fun not():Student{
    return Student(this.name.reversed(),this.age)
}

+a a.unaryPlus()

-a a.unaryMinus()

!a a.not()

a– a.dec()

a++ a.inc()

operator fun inc():Student{
    return Student(name,age++)
}

operator fun dec():Student{
    return Student("name",age++)
}

a+=b a.plusAssign(b)

a-=b a.minusAssign(b)

a*=b a.timesAssign(b)

a/=b a.divAssign(b)

a%= b a.remAssign(b)

同时定义+和+=可能会产生歧义

a>b a.compareTo(b) >0

a<b a.compareTo(b) <=0

a>=b a.compareTo(b) >0

a<=b a.compareTo(b) <=0

() invoke

6.中缀函数

println(10 shl 2) 左移位

调用可以省略点和括号

要求:

1.必须是成员函数

2.只能有一个参数

3,参数不能有默认值

class Student constructor(var name:String,var age:Int){
    operator fun plus(another:Student):Student{
        return Student(this.name+another.name,another.age+this.age)
    }

    operator fun not():Student{
        return Student(this.name.reversed(),this.age)
    }

    operator fun inc():Student{
        return Student(name,age++)
    }

    operator fun dec():Student{
        return Student("name",age++)
    }

    infix fun test(string:String):String{
        return name+string
    }
}


package demo2

fun main(){
    val stu = Student("zs",11)
    println(stu test "hahaha")
    //也可以当成普通函数调用
    println(stu.test("hahaha"))
}

7.空值和空类型

当我们直接给一个变量赋值空null是kotlin在编译阶段就会报错

val ss:String = null

加上?:表明这是一个可空的类型

val ss:String ?= null

加上!!强制调用

ss!!.getdata()

安全访问方法

ss?.getdata()
val s:Student? = null
val a = s?.getdata() ?: "hahah"
println(a)

?: 类似与三元运算符 ,当对象为空是会执行?:右边的函数

8.解构

component1即为第一个解构的参数

解构()里的变量名可随意取

class Car(var name:String,var price:Int) {
    operator fun component1() = name
    operator fun component2() = price
}

fun main(){
    val car:Car = Car("ll",1000)
    val (a,b) = car
    println(a)
    println(b)
    //如果不需要第一个解构的值
    val (_,b) = car
}

应用-》在lamda表达式中使用

val func1:(Car)->String = { (a,b) ->
           a+b.toString()
      }
println(func1(car))

7.类与继承

1.权限声明

public

private

protected

internal 只能在当前项目内访问,当别人引用我们的项目时,不能使用

2.类的继承

声明继承

被继承的类要要声明open

public open class Car(internal var name:String, public var price:Int) {
    operator fun component1() = name
    operator fun component2() = price
}

public class SuperCar:Car("1",1000){
    
}
public open class Car(internal var name:String, public var price:Int) {
    operator fun component1() = name
    operator fun component2() = price
}

public class SportCar(name:String,price: Int):Car("1",1000){
    
}

当子类未声明主构造函数

public open class Car(internal var name:String, public var price:Int) {
    operator fun component1() = name
    operator fun component2() = price
}

public class SportCar:Car{
    constructor(name:String,price: Int):super("1",1000)
}

3.方法的重写(覆盖)

可以通过super关键字调用父类的方法

public open class Car(internal var name:String, public var price:Int) {
    operator fun component1() = name
    operator fun component2() = price
    open fun run(data:String){
        println(data+"1")
    }
}

public class SuperCar:Car("1",1000){
    override fun run(data: String) {
        super.run(data)
    }
}

重写成员变量

public open class Car() {
    open var name:String = "zs"
}

public class sportcar: Car(){
    override var name: String = "ls"
}

4.顶层Any类

相当于java的Object

=== 判断是否是同一个引用对象

5.抽象类

abstract class annimal{
    abstract var name:String
    abstract fun say()
}

class cat(override var name: String) :annimal(){
    override fun say() {
        println("miao")
    }
}
abstract class annimal{
    abstract var name:String
    abstract fun say()
}

class cat :annimal(){
    override var name:String = "cat"
    override fun say() {
        println("miao")
    }
}

6.接口

接口的所有成员变量和类方法都是抽象的,因此可以省略abstract不写

interface A{
    val name:String
    fun run1():String
}

interface B{
    val age:Int
    fun run2():String
}

class stu() :A,B{
    override val age: Int = 16
    override val name: String ="NAME"
    override fun run1(): String {
        return "1"
    }

    override fun run2(): String {
        return "2"
    }
}

接口也可以实现默认方法

interface A{
    val name:String
    fun run1():String
}

interface B{
    val age:Int
    fun run2():String = "AGE"
}

class stu() :A,B{
    override val age: Int = 16
    override val name: String ="NAME"
    override fun run1(): String {
        return "1"
    }

    override fun run2(): String {
        return "2"
    }
}

如果继承的两个接口有重复函数可以使用<>消除歧义

interface A{
    fun run():String = "NAME"
}

interface B{
    fun run():String = "AGE"
}

class stu() :A,B{
    override fun run(): String = super<A>.run();
    override fun run(): String = super<B>.run();
}

7.类的扩展

class animal{
    fun test(){
        println("HAHAHA")
    }
}

fun animal.test() = println("HELLO")

fun main(){
    animal().test()
}

当有重复函数是扩展会失效

添加属性,此时field无法使用

类的扩展会受到访问权限的影响

var animal.NAME: String
    get() = ""
    set(value){
        println("SET")
    }

在扩展的函数中可以直接使用类的成员变量,可以不使用this关键字

class animal{
    val name:String = "JKL" 
}
fun animal.test() = { 
    println(name)
}

指定调用的函数

class A{
    fun hello(){
        println("Hello")
    }
}

class B(private val a:A){
    fun A.test(){
        hello()
        this.hello()
        this@B.hello()
    }
    
    fun hello(){
        println("HELLO")
    }
}

将一个扩展函数作为参数传递到一个函数类型变量,在具体操作前要增加类型名称

fun main(){
    val func:String.() -> Int = {
        this.length
    }
    println("hahahahhaha".func())
    println(func("hello"))
}

8.范型

1.范型

可以直接接收数值,自动转换类型

class Score<T>(var name:T){
    
}

fun main(){
    val stu = Score("123")
}

2.官方高阶扩展函数

apply 传入一个lambda表达式,也就是我们要如何操作这个对象

let 执行一个lamda表达式并将得到的结果作为返回值

also 与apply类似

run 与let类似

fun main(){
    val a:Any = Any()
    a.apply {  }
}

3.协变和逆变

class Num<T>(var name:T)

fun main(){
    val v1:Num<Int> = Num<Int>(1) 
    val v2:Num<Number> = v1   //报错
}

虽然Number是Int的父类但是缺类型不匹配

协变 父类接收子类

逆变 子类接收父类

抗变 类型不相关Test<Int>与Test<Number>无关

使用out开启协变,使用in开启逆变

//协变
class Num<T>(var name:T)

fun main(){
    val v1:Num<Int> = Num<Int>(1)
    val v2:Num<out Number> = v1
}
//逆变
class Num<T>(var name:T)

fun main(){
    val v1:Num<Any> = Num<Any>(1)
    val v2:Num<in Number> = v1
}

可以使用*来代指任意类型

4.范型的界限

限制范型的类型

//限制上界为Number
class Num<T : Number>(var name:T)

fun main(){
    val v1:Num<Int> = Num<Int>(1)
    val v2:Num<out Number> = v1
}
class Num<T>(var name:T)
    where T:C,T:D
open class C
open class D

也可以直接在类或接口的参数中声明

interface Test<out T>{
    fun test():T
}

5.类型擦除

内联函数的类型擦除与普通函数的

reified通过该关键字具化类型

inline fun <reified T> test(value:Any):Boolean{
    return value is T
}

fun main(){
    val result = test<String>("1")
    println(result)
}

9.数组

1.定义和遍历数组

fun main(){
    val array:Array<Int> = arrayOf(1,2,3,4,6,5)
    for (element in array){
        println(element)
    }
}

获取长度 array.size

数组在创建完成后数组容量和元素类型是固定不变的后续无法修改

fun main(){
    val array:Array<Int> = arrayOf(1,2,3,4,6,5)
	//遍历下标和元素
    for ((index,element) in array.withIndex()){
        println(array[index])
        println(index)
        println(element)
    }
}

数组的创建和使用

array.forEach { println(it) }
//第一个参数为间隔符,第二个参数为开始字符串,第三个为结束字符串
println(array.joinToString(",","[","]"))
//创造一个长度为5,值都为123的字符串数组
val array:Array<String> = Array(5){"1234"}

2.数组的操作

==号判断内容是否相同

val array1:Array<String> = Array(5){"1234"}
val array2:Array<String> = Array(5){"1234"}
println(array1.contentEquals(array2))   //=>true

拷贝数组

可以指定参数,为拷贝的数量如果数量大于数组大小会用空填充

//执行拷贝
var array3:Array<String> = array2.copyOf()
//指定拷贝范围
var array4:Array<String> = array2.copyOfRange(2,3)

分割数组

var array5:Array<String> = array2.sliceArray(1..3)

数组可以用加号进行合并

判断指定元素在不在数组

array2.contains("1234")
"1234" in array2

快速查找元素在哪一位置

array2.indexOf("1234")

reversedarray反转数组

sort排序 sortDesc倒排序

可以重写一个类的compareTo方法指定排序规则

class B():Comparable<B>{
    override fun compareTo(other: B): Int {
        return B.age - A.age
    }
}

vararg 可以接收任意个同类型的参数

3.基本数组类型

Kotlin			Java
ByteArray		byte[]
CharArray		char[]
ShortArray		short[]
IntArray		int[]
LongArray		long[]
DoubleArray		double[]
FloatArray		float[]
BooleanArray	boolean[]

4.List

可变的列表,可以插入和删除

fun main(){
    val list:MutableList<String> = mutableListOf("1","2","3");
    list.add("4")
    list.add(1,"5")
    list.remove("1")
    list.removeAt(1)
    println(list)
}

不可变的列表,无法插入删除

val list1:List<Int> = listOf(1,2,3)

可以用{}进行初始化赋值

使用for in 进行遍历

val list2:List<Int> = List<Int>(3){10}
for (ele in list2){
    println(ele)
}

5.Set

没有重复元素,可用于去重

不能在指定位置插入

var set:MutableSet<Int> = mutableSetOf(1,2,3)
//简单的获取元素
println(set.elementAt(0))

集合的运算

//并集
println(set1 union  set2)
println(set1 + set2)
//交集
println(set1 intersect set2)
//差集
println(set1 - set2)
println(set1 subtract set2)

不同类型的set

val set1:SortedSet<Int> = sortedSetOf(9,5,3,19) //自动排序
println(set1)
val set2:HashSet<Int> = hashSetOf(1,2,3) // 无序且不重复
println(set2)

6.Map

Pair

val pair:Pair<Int,String> = 10001 to "zs"

创建Map

map[键]获取值

val map:MutableMap<Int,String> = mutableMapOf(
    1001 to "zs",
    1002 to "ls"
)
//获取所有的键
println(map.keys)
//获取所有的值
println(map.values)

遍历

for in

for each

map.forEach{(k,v) -> println(k.toString()+v) }

可以直接+=添加新键值对

键不能重复,否则数据会被覆盖

map.put()
map.putAll()

7.迭代器

val iterator:Iterator<String> = array1.iterator()
println(iterator.next())
println(iterator.next())
println(iterator.next())
println(iterator.next())

遍历数组

val iterator:Iterator<String> = array1.iterator()
while(iterator.hasNext()){
    println(iterator.next())
}

ListIterator可以实现双向遍历

MutableIterable迭代器 可以在遍历的时候进行删除

8.数组的扩展操作

map 类似于js的map对每一个元素进行操作并且返回一个值

val list:MutableList<String> = mutableListOf("AAA","BB","DDD")
val list2 : MutableList<Int> = list.map { it.length }.toMutableList()
println(list2.joinToString())

遍历map

val map:Map<String,Int> = mapOf(
    "AAA" to 1,
    "BB" to 2,
    "CCCC" to 3
)
val map1: Map<Int, Int> = map.mapKeys { it.key.length }
val map2 : Map<String,String> = map.mapValues { it.value.toString() }

zip

unzip

val zipmap: List<Pair<String, Int>> = list1.zip(list2)
println(zipmap)
val pair:Pair<List<String>, List<Int>> = zipmap.unzip()
println(pair)

associate将列表映射为一个map集合

val associates : Map<String,Int> = list1.associate { it to it.length }
println(associates)

扁平化处理多维数组

 val array= Array(10, {Array(10){0}})
val list = List(10,{List(10){0} })
//展平
println(array.flatten())

array.flatMap { }在遍历的同时映射

filter过滤操作

list1.filter { it >= 10 }
//过滤不为空的元素
list1.filterNotNull()

10.序列

在使用时才会执行其中的语句

val sequence:Sequence<Int> = generateSequence {
    println("构造")
    10 //返回值
}

println(sequence.iterator().next())

普通的list,在执行操作时就会调用函数

val list:List<String> = mutableListOf("AAA","BB","CCC","dd","EEE","FF")
val result = list.filter {
    println("执行1")
    it.length > 2
}.map {
    println("执行2")
    it.lowercase()
}.take(2)
println(result)

进行优化,在调用使用的时候才会执行内部

数据量庞大时推荐使用

val list:List<String> = mutableListOf("AAA","BB","CCC","dd","EEE","FF")
val result = list.asSequence().filter {
    println("执行1")
    it.length > 2
}.map {
    println("执行2")
    it.lowercase()
}.take(2)
println(result.joinToString())

11.特殊的类型

1.数据类型

本质是class

data class Data(val name:String,val age:Int){
    
}

加上data关键字后

自动生成.equals()/.hashCode()

.toString()

.componentN()

.copy()方法

数据类不能是抽象类

主构造函数必须有一个参数

主构造函数变量必须是var或者val

编译器只会根据构造函数生成,因此可以将参数移出主构造函数,equals方法就不会考虑到写在主构造函数之外的变量

2.枚举类型

加上enum关键字

枚举类可以重写内部的抽象函数,当继承了一个接口时,可以在每个枚举类中重写,或者在定义枚举类的类中重写

fun main(){
	println(Status.ERR.code)
}

enum class Status(var code:String){
    ERR("0"),SUCC("1"),COMP("2")
}

可以定义成员函数

fun main(){   
	val status = Status.ERR
    println(status.code)
    println(status.isERR())
}

enum class Status(var code:String){
    ERR("0"),SUCC("1"),COMP("2"); //使用;进行分隔

    fun isERR() = this == ERR
}

定义成员变量

fun main(){
    println(status.state)
}

enum class Status(var code:String){
    ERR("0"),SUCC("1"),COMP("2");

    val state:Int = 10
}

使用when

val message:String = when(status){
    Status.ERR -> "错误"
    Status.SUCC -> "成功"
    Status.COMP -> "运行"
}
println(message)

entries获取整个枚举类

val statuslist = Status.entries
println(statuslist.joinToString())

12.匿名类

1.匿名类

使用object关键字声明匿名类,并且可以用变量接收

fun main(){
    val stu = object {
        fun test():String{
            return "123"
        }
    }
    val message = stu.test()
    println(message)
}

如果接口只有一个函数,可以采用简洁写法实现匿名类

fun interface Krunnerable{
    fun test()
}

fun main(){
    val stu = object {
        fun test():String{
            return "123"
        }
    }
    val message = stu.test()
    println(message)
    
    val runnerable = Krunnerable{
        println("1234")
    }
}

单例对象

object Run{ 通过objext关键字
    val name:String = "name"
    override fun toString(): String {
        return super.toString()
    }
}

fun main(){
    val run = Run //单例对象直接使用类型得到实例化对象
    println(run.toString()) //可以直接使用内部的方法
}

2.伴生对象

companion

class Animal(val name:String){
    //使用companion 关键字定义半生对象
    companion object Cat{
        val age:Int = 90
        fun test(){
            println("test")
        }
    }
}

fun main() {
    //可以直接使用外面的类名访问内部的方法
    Animal.test()
}

13.委托模式

使用by关键字

//定义接口
interface Base{
    fun test()
}
//接口实现
class BaseImpl():Base{
    override fun test() {
        println("test")
    }
}
//委托代理
class Work(val base:BaseImpl) : Base by base //实现Base接口,但是让base帮忙重写

fun main() {
    //可以直接使用外面的类名访问内部的方法
    val work = Work(BaseImpl())
	work.test()
}

使用预设代理lazy在调用时赋值

class Exe(){
    val per:String by lazy { "geren" }
}
fun main() {
    val message:String = Exe().per
    println(message)
}

属性可以委托属性代理

class Exe1(val name:String){
    val per:String by ::name
}

设置观察者

//设置观察者
class Exe2(val name:String){
    val per:String by Delegates.observable("初始值"){
        prop,new,old -> println("属性值为${prop},新值为${new},旧值为${old}")
    }
}

14.密封对象

sealed class A

不能在外部继承使用以及实例化(模块内部)

密封类是可以被继承的,密封类的子类也可以是密封类

15.异常机制

1.异常的定义

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at demo1.Test5Kt.div(test5.kt:47)
	at demo1.Test5Kt.main(test5.kt:42)
	at demo1.Test5Kt.main(test5.kt)

自定义Exception

class myException(override val message: String?):Exception(message)

private fun div(x:Int, y:Int):Int{
    if (y==0) throw myException("div by zero")
    return x / y
}

2.捕获异常

val array:MutableList<Int> = mutableListOf(1,2,9)
try{
    println(array[3])
}catch (e:IndexOutOfBoundsException){
    e.printStackTrace()
}
println("after")

多个catch

val array:MutableList<Int> = mutableListOf(1,2,9)
try{
    println(array[3])
}catch (e:IndexOutOfBoundsException){
    e.printStackTrace()
}catch (e:Exception){
    e.printStackTrace()
}