前言
Kotlin作为一门新的语言,并被Google在17年I/O大会上,成为了官方的Android开发语言。一直也有关注,但也只是简单了解了一下,听说差不多是在java基础上封装了很多语法糖,但当我真正开始学习的时候发现并非如此,当你真正的去学习Kotlin时这种使用及编程时,才会体会到它的强大。
1、函数与变量
(1)先来一个简单的函数声明
fun main(args: Array<String>) {
println("Hello, world")
}
函数声明以fun关键字开始,没有任何返回的函数。
复杂一些的:函数声明以fun关键字开始 - 函数名 - 函数列表 - 返回类型,里面为函数体。
/**
* 函数声明以fun关键字开始 - 函数名 - 函数列表 - 返回类型,里面为函数体
* 返回值的函数,类型Int
*
* 语句与表达式的区别在于:
* 表达式有值,并且能作为另一个表达式的一部分使用
* 而语句总是包围着它的代码块中的顶层元素,并且没有自己的值
*
* 在java中所有的控制语句都是语句,而在Kotlin中除了循环(for、do、do/while)以外大多数控制结构都是表达式
*
* 另一方面,java中赋值操作是表达式,而在Kotlin中反而是语句,
* 这有助于避免比较和赋值之间的混淆,而这种混淆是常见的错误来源
*/
fun max(a: Int, b: Int): Int {
// 在Kotlin中,if语句是有结果值的表达式,而不是语句,与java中的三元运算符相似:(a > b) ? a : b。
return if (a > b) a else b
}
代码中已经有非常详细的阐述了,不再做阐述。
更简单的写法:
/**
* 表达式函数体,与上面的max方法函数一样的结果,更简单
* 使用单个表达式作为完整的函数体,并去掉花括号和return语句
*
* 如果函数体写在花括号中,则称这个函数有代码块体,如果直接返回一个表达式,它就有表达式体
*/
fun max2(a: Int, b: Int): Int = if (a > b) a else b
进一步简化max函数,省掉返回类型:
/**
* 进一步简化max函数,省掉返回类型,与上面的max方法函数一样的结果
*
* 每个变量、表达式和函数都有返回类型,编译器会自行类型推导
*
* 注意:只有表达式体函数的返回类型可以省略。
* 而对于有返回值的代码块体函数,必须显示地写出返回类型和return语句
*/
fun max3(a: Int, b: Int) = if (a > b) a else b
(2)变量声明
/**
* 省略了类型声明,也可以显式的指定变量的类型
*
* 有一个变量初始化器
*
* 如果不指定变量的类型,编译器会分析初始化器表达式的值,并把它的类型作为变量的类型
*/
val question = "aa"
val answer = 12
val answer_2: Int = 12
// 7.5 * 10^6
val yearsToCompute = 7.5e6
如果变量没有初始化器,需要显式地指定它的类型,如果不能提供可以赋值给这个变量的值的信息,编译器就无法推断它的类型:
/**
* 如果变量没有初始化器,需要显式地指定它的类型
*
* 如果不能提供可以赋值给这个变量的值的信息,编译器就无法推断它的类型
*/
val answer3: Int
answer3 = 12
打印非常简单的使用:
// 打印,几乎里面能够直接传入非常多的数据类型
println(answer3)
变量声明关键字有:val和var
val ------- > 来自value,不可变引用,对应java中的final变量。
var ------- >来自variable,可变引用,对应java普通非final变量。
更简单的字符串格式化:字符串模板
val name = "lh"
println("name is: $name")
2、类和属性
(1)类、属性的声明:冒号后面接的就是接口
package com.lh.customviewlearn.testkotlin
import java.io.Serializable
/**
* 只有数据没有其他代码通常称为值对象
*
* 类默认public
* val属性只读属性:默认会自动生成一个存储值的字段和一个简单的getter访问器方法
* var属性可变(可写)属性:生成一个字段和一个getter、一个setter访问器方法
*
* 也可声明自定义的访问器,使用不同的逻辑来计算和更新属性的值
*
* @author LuoHao
* Created on 2018/4/5 11:52
*/
class Person(
val name: String,
var isMarried: Boolean
) : Serializable
(2) 使用类
java 中:可以看到和java类使用没什么区别
Person p = new Person("", true);
p.getName();
p.isMarried();
p.setMarried(false);
Kotlin 中:调用构造方法不需要关键字new,可以直接访问对象属性,但调用的是getter。
/**
* 类的使用
*/
// 调用构造方法不需要关键字new
val person = Person("luohao", true)
// Kotlin中,可以直接访问对象属性,但调用的是getter
println(person.name)
println(person.isMarried)
// 直接赋值
person.isMarried = false
(3)自定义访问器
如下声明属性的getter
/**
* 自定义访问器
*
* @author LuoHao
* Created on 2018/4/6 21:38
*/
class Rectangle(val height: Int, val width: Int) {
// 声明属性的getter
// 自定义访问器,通过计算是否相等判断是否是正方形,不需要一个单独的字段来存储这个信息(是否是正方形)
// 属性isSquare不需要字段来保存它的值,它只是一个自定义实现的getter,它的值是每次访问属性时计算出来的
val isSquare: Boolean
get() {
return height == width
}
// 注意:如果在java中访问这个属性,可以调用 isSquare()方法
// 同等实现,不需要带花括号的完整语法,对这个属性的调用依然不变
val isSquare2: Boolean
get() = height == width
val square: Boolean = height == width
// val square: Boolean = if (height == width) true else false
fun isSquare4(): Boolean = true
}
/**
* 顶层函数 可以直接写在类的外面,这点和java不同
* Kotlin 中会导入顶层函数的函数名称来使用该函数
*/
fun isSquare4(): Boolean = false
java中使用:
Rectangle rectangle = new Rectangle(1, 3);
rectangle.isSquare(); // 对应 val isSquare: Boolean属性
rectangle.isSquare2(); // 对应 val isSquare2: Boolean属性
rectangle.isSquare4(); // 对应Rectangle类里面声明的fun isSquare4():Boolean 方法
isSquare4(); // 对应 顶层函数 fun isSquare4():Boolean 方法
Kotlin 中使用:
val rectangle = Rectangle(1, 2)
println(rectangle.isSquare)
println(rectangle.square)
println(rectangle.isSquare2)
rectangle.isSquare4()
// Kotlin 中会导入顶层函数的函数名称来使用该函数
isSquare4()
(4)Kotlin 中源码布局:目录和包结构,这点和java不同
在Rectangle.kt这个文件中,你可以做的事情有很多,如下:
/**
* 包层级结构不需要遵循目录层级结构,跟java刚好相反,当然推荐遵循java的目录布局结构是个不错的实践
* 但是也应该毫不犹豫地把多个类放进同一个文件中,特别是那些很小的类(在Kotlin中,类通常很小)
*
* kotlin 中可以将多个类放在同一个文件中,并且文件的名字还可以随意选择
* 意思就是:多个类的类名都可以完全和文件的名称不一样,这点跟java完全不一样,java必须类名和文件名相同
* 如将上面这个Rectangle类名字改为其他名字,文件名依然叫Rectangle.kt,也不会有错
*/
class Person_2(
val name: String,
var isMarried: Boolean
)
/**
* 声明变量
*/
val isSquare: Boolean = true
/**
* 顶层函数
* Kotlin 中会导入顶层函数的函数名称来使用该函数
*/
fun isSquare4(): Boolean = false
fun createRandomRectangle(): Rectangle {
val random = Random()
return Rectangle(random.nextInt(), random.nextInt())
}
如上,基本都是这些了,是不是和java不一样,哈哈~
3、Kotlin 中的控制结构:表示和处理选择:枚举和when,when 结构 可以替代java中 switch 结构,但 when 结构更强大。
(1)先来看下Kotlin 中声明枚举,Kotlin 中定义枚举,比java中多了 class 关键字,Kotlin 中 enum 是一个所谓的软关键字:只有当它出现在 class 前面时才有特殊意义,在其他地方可以把它当做,普通的名称使用。与此不同的是,class 仍然是个关键字。
/**
* Kotlin 中定义枚举,比java中多了 class 关键字
* Kotlin 中 enum 是一个所谓的软关键字:只有当它出现在 class 前面时才有特殊意义,在其他地方可以把它当做
* 普通的名称使用。与此不同的是,class 仍然是个关键字
*/
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
可以给枚举类声明属性和方法:在每个常量创建的时候必须指定属性值,并且最后一个后面必须像java一样需要有分号,这个分号是 Kotlin 语法中唯一必须使用分号的地方:如果要在枚举中定义任何的方法,就要使用分号把枚举常量列表和方法定义分开。
使用 when 来处理枚举类。
/**
* 和 java 一样,枚举并不是值的列表:可以给枚举类声明属性和方法。
* 如下声明了枚举常量的属性
*/
enum class Color2(val r: Int, val g: Int, val b: Int) {
/**
* 在每个常量创建的时候必须指定属性值,并且最后一个后面必须像java一样需要有分号
*
* 这个分号是 Kotlin 语法中唯一必须使用分号的地方:如果要在枚举中定义任何的方法,
* 就要使用分号把枚举常量列表和方法定义分开。
*/
RED(255, 0, 0),
YELLOW(255, 156, 120),
WHITE(255, 120, 1),
ORANGE(255, 165, 0);
/**
* 给枚举类定义一个方法
*/
fun rgb(): Int {
return (r * 256 + g) * 256 + b
}
fun rgb2() = (r * 256 + g) * 256 + b
// 使用 when 来处理枚举类
fun getMnemonic3(color: Color2): String {
return when (color) {
// 枚举常量的完整名称使用
Color2.RED -> "RED"
// 枚举常量直接名称使用
ORANGE -> "ORANGE"
Color2.YELLOW -> "YELLOW"
Color2.WHITE -> "WHITE"
}
}
// 使用 when 来处理枚举类
fun getMnemonic2(color: Color2): String {
val s = when (color) {
// 枚举常量的完整名称使用
Color2.RED -> {
"RED"
}
// 枚举常量直接名称使用
ORANGE -> "ORANGE"
Color2.YELLOW -> "YELLOW"
Color2.WHITE -> "WHITE"
}
return s
}
// 使用 when 来处理枚举类
fun getMnemonic(color: Color2): String {
val s: String
s = when (color) {
// 枚举常量的完整名称使用
Color2.RED -> "RED"
// 枚举常量直接名称使用
ORANGE -> "ORANGE"
Color2.YELLOW -> "YELLOW"
Color2.WHITE -> "WHITE"
}
return s
}
}
写在类外面:
/**
* 使用 when 来处理枚举类 直接返回一个 when 表达式,返回对应的字符串
* 不需要每个分支都写上 break 语句,如果匹配成功只会对应的分支执行
* 也可以把多个配置值合并到同一个分支,使用逗号分隔即可
*/
fun getMnemonic(color: Color2) =
when (color) {
// 把多个配置值合并到同一个分支,使用逗号分隔即可
Color2.RED, Color2.YELLOW -> "RED"
Color2.ORANGE -> "ORANGE"
// 其他类型使用 else
else -> "Other Value"
}
使用:
fun testColor() {
Color2.ORANGE.getMnemonic2(Color2.RED)
println(getMnemonic(Color2.ORANGE))
}
when 结构中可以使用任意对象,java的switch中必须使用常量(枚举常量、字符串、数字值)作为分支条件:组合条件
// when 结构中可以使用任意对象,java的switch中必须使用常量(枚举常量、字符串、数字值)作为分支条件
// 组合条件
fun mix(c1: Color2, c2: Color2) =
// setOf 是创建一个Set对象
when (setOf(c1, c2)) {
setOf(Color2.RED, Color2.ORANGE) -> Color2.ORANGE
setOf(Color2.YELLOW, Color2.WHITE) -> Color2.WHITE
// 匹配不到,其他情况
else -> throw Exception("Dirty color")
}
mix方法的优化:
/**
* 不带任何参数的 when
*
* 该方法是上面mix方法的优化,原因是:上面的方法会频繁创建Set对象,
* 使用这个方法可以避免创建额外的垃圾对象
*
* 如果没有给 when 表达式提供参数,分支条件就是任意的布尔表达式。
*/
fun mixOptimized(c1: Color2, c2: Color2) =
when {
(c1 == Color2.RED && c2 == Color2.ORANGE) ||
(c1 == Color2.ORANGE && c2 == Color2.RED) ->
Color2.ORANGE
(c1 == Color2.WHITE && c2 == Color2.YELLOW) ||
(c1 == Color2.YELLOW && c2 == Color2.WHITE) ->
Color2.WHITE
else -> throw Exception("Dirty color")
}
(2)Kotlin 中 智能转换:合并类型检查和转换。来进行(1+2)+4 简单的运算表达式求值。
声明一个接口和两个类:
// 智能转换:合并类型检查和转换,(1+2)+4 简单的运算表达式求值,存储在一个树状结构中Num永远是叶子节点,
interface Expr
// 接口实现使用冒号(:)后加接口名称,简单的值对象,只有一个属性value,实现了Expr接口
class Num(val value: Int) : Expr
// Sum 运算的实参可以是任何的Expr:Num或者另一个Sum,Sum类存储了Expr类型的实参left和right的引用
class Sum(val left: Expr, var right: Expr) : Expr {
val right2: Expr
get() {
return right
}
// 注意 var 和val 自定义访问器的不同赋值方式
var left2: Expr = Num(1)
get() {
return left
}
}
需要计算的为:Sum(Sum(Num(1) + Num(2)), Num(4))
// Sum(Sum(Num(1) + Num(2)), Num(4))
// Expr接口有两种实现:1,如果表达式是一个数字,直接返回它的值;
// 2、如果是一次求和,得先计算左右两个表达式的值,再返回它们的和
fun eval(e: Expr): Int {
// Kotlin 中方法中的变量是val类型的,不能重新复制
// e = Num(1)
// Kotlin 中使用 is 关键字来检查判断一个变量是否是某种类型,与java中的 instanceOf 相似
// 但在java还需要显示的加上类型转换;
// 而Kotlin 中则不需要,直接当做检查过的类型使用,是编译器执行了类型转换,这种行为称为智能转换。
if (e is Num) {
// 显示地转换成类型Num是多余的
val n = e as Num
return n.value
}
if (e is Sum) {
// 变量 e 被智能的转换了类型
return eval(e.right) + eval(e.left) + eval(e.left2) + eval(e.right2)
}
throw IllegalArgumentException("Unknown expression")
}
优化,使用有返回值的if作为函数体:
// java 中三元运算符 if(a > b) a else b 和 a > b ? a : b
// Kotlin 没有,因为if表达式有返回值,可以使用表达式体语法重写eval函数,
// 去掉return语句和花括号,使用有返回值的if表达式作为函数体
fun evalOptimized(e: Expr): Int =
if (e is Num)
// 如果if分支中只有一个表达式,花括号是可以省略的,
e.value + 1
else if (e is Sum) {
// 如果if分支是一个代码块,需要花括号,代码块中的最后一个表达式会被作为结果返回的
if (e.left is Num) e.left.value + 1
evalOptimized(e.right) + evalOptimized(e.left)
} else {
throw IllegalArgumentException("UnKnown expression")
}
再次优化 使用 when 代替if层叠:
/**
* 再次优化 使用 when 代替if层叠
*
* when 表达式并不仅限于检查值是否相等,这里是另一种when分支的形式,允许检查when实参值的类型,并应用了智能转换
*
* 当分支逻辑太过复杂时,可以使用代码块作为分支体,并且此时必须使用花括号,代码块中的最后一个表达式会被作为结果返回的
*/
fun evalOptimized2(e: Expr): Int =
when (e) {
// 应用了智能转换
// 检查实参类型的 when 分支
is Num -> {
// 如果if分支是一个代码块,需要花括号,代码块中的最后一个表达式会被作为结果返回的
println("num: ${e.value}")
e.value
}
is Sum -> {
// evalOptimized2(e.left) + evalOptimized2(e.right)
val left = evalOptimized2(e.left)
val right = evalOptimized2(e.right)
println("sum: $left + $right")
// 规则:代码块中最后的表达式就是结果,在所有代码块并期望得到一个结果的地方成立。
// 但该规则对于常规函数不成立。
left + right
}
else ->
throw IllegalArgumentException("Unknown expression")
}
使用:
fun textNum() {
println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
println(evalOptimized(Sum(Sum(Num(1), Num(2)), Num(4))))
println(evalOptimized2(Sum(Sum(Num(1), Num(2)), Num(4))))
}
4、迭代事物:while 循环 和 for 循环
(1)while 循环和java中没什么区别
// 迭代事物:while 循环 和 for 循环
// while 循环和java中没什么区别
fun whileTest() {
val condition = false
// 当condition为true时才执行循环体
while (condition) {
}
// 循环体第一次会无条件地执行。此后,当condition为true时才执行
do {
} while (condition)
}
(2)迭代数字:区间和数列
Kotlin 中没有常规的java for循环,Kotlin使用了区间概念,如下:
// 迭代数字:区间和数列
// Kotlin 中没有常规的java for循环,Kotlin使用了区间概念
// 区间本质上就是两个值之间的间隙,这两个值通常是数字:一个起始值,一个结束值。使用(..)运算符来表示区间:
// 如 val oneToTen = 1..10 注意:Kotlin 中区间是闭合的或者包含的,意味着第二个值(10)也是区间的一部分
// 循环迭代其中所有的值,如果能迭代区间所有的值,这样的区间被称作数列。
fun fizzBuzz(i: Int) = when {
// % 和java一样是取模运算符,是否能被15整除
i % 15 == 0 -> "FizzBuzz "
i % 5 == 0 -> "Fizz "
i % 3 == 0 -> "Buzz "
else -> "$i "
}
使用:
// 区间
for (i in 1..100) {
print(fizzBuzz(i))
}
迭代带步长的区间,迭代一个带步长的数列,允许跳过一些数字,步长也可以是负数,负数时是递减的。
从100开始倒着计数并且只记偶数:
// 迭代带步长的区间,迭代一个带步长的数列,允许跳过一些数字,步长也可以是负数,负数时是递减的
// 从100开始倒着计数并且只记偶数
// 100 downTo 1 表示是递减的数列(步长为-1),然后step把步长的绝对值变为了2,但方向保持不变(事实上,步长被设置成了-2)
// ..语法始终创建的是包含结束值(100)的区间。若不想包含则是半闭合区间,使用 until 函数可以创建。
for (i in 100 downTo 1 step 2) {
print(fizzBuzz(i))
}
语法始终创建的是包含结束值(100)的区间。若不想包含则是半闭合区间,使用 until 函数可以创建。
// ..语法始终创建的是包含结束值(100)的区间。若不想包含则是半闭合区间,使用 until 函数可以创建。
// for (i in 0 until 100)等同于 for (i in 0..100 - 1)
// 但推荐这个,更清晰地表达了意图
for (i in 0 until 100) {
print(fizzBuzz(i))
}
// 不推荐
for (i in 0..100 - 1) {
print(fizzBuzz(i))
}
(3)迭代map,迭代集合
// 使用TreeMap 让键排序
val binaryReps = TreeMap<Char, String>()
// .. 语法不仅可以创建数字区间,还可以创建字符区间
// 使用字符区间迭代A到F的字符,包括F
for (c in 'A'..'F') {
// ASCII码转换成二进制
val binary = Integer.toBinaryString(c.toInt())
// binaryReps.put(c, binary)
// 推荐这个赋值,不需要使用put 和 get
binaryReps[c] = binary
// 获取值
// val aa = binaryReps[c]
}
// 迭代map,把键和值赋给两个变量
for ((letter, binary) in binaryReps) {
println("$letter = $binary")
}
展开语法在迭代集合的同时跟踪当前项的下标,不需要创建一个单独的变量来存储下标并手动增加它:
// 展开语法在迭代集合的同时跟踪当前项的下标,不需要创建一个单独的变量来存储下标并手动增加它
val list = arrayListOf("10", "11", "12")
// 迭代集合时使用下标
for ((index, element) in list.withIndex()) {
println("$index: $element")
}
// 打印: 0: 10 1: 11 2: 12
关键字in不仅可以迭代区间和集合,还可以用in来检查区间或集合是否包含了某个值,或者使用in的逆运算 !in
// 关键字in不仅可以迭代区间和集合,还可以用in来检查区间或集合是否包含了某个值
// 使用in的逆运算 !in
// 判断字符是否是英文字母
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
// String类型匹配
fun isLetter2(s: String) = s in "a".."z" || s in "A".."Z"
// 判断不是数字
fun isNotDigit(c: Char) = c !in '0'..'9'
// 用in检查作为when表达式
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "Tt's a digit!"
// 逗号隔离多种检查的区间
in 'a'..'z', in 'A'..'Z' -> "It's a letter!"
else -> "I don't know..."
}
使用:
// 关键字in不仅可以迭代区间和集合,还可以用in来检查区间或集合是否包含了某个值
// 使用in的逆运算 !in
println(isLetter('a')) // true
println(isLetter2("a")) // true
println(isNotDigit('b')) // true
println(recognize('8'))
in 支持实例比较操作的任意类(实现了 Comparable 接口的类),就能创建这种类型的对象的区间:
// in 支持实例比较操作的任意类(实现了 Comparable 接口的类),就能创建这种类型的对象的区间
println("Kotlin" in "Java".."Scala") // true
in 检查同样适用于集合 如 Set:
// in 检查同样适用于集合 如 Set
println("Kotlin" in setOf("Java", "Scala")) // false
5、Kotlin 中的异常
// Kotlin 中的异常
// 异常处理和java中相似,函数可以正常结束,也可以在出现错误的时候抛出异常
// 方法的调用者能捕获这个异常并能处理它,如果没有被处理,异常将沿着调用栈再次抛出
fun dealException(percentage: Int) {
if (percentage !in 0..100) {
throw IllegalArgumentException("A percentage value must be between 0 and 100: $percentage")
}
// throw 在Kotlin中,相比java中不同的是,Kotlin 中throw结构是一个表达式,能作为另一个表达式的一部分使用
// 注意:在Kotlin 中可以创建和方法参数一样的变量
val number =
if (percentage in 0..100) percentage
else throw IllegalArgumentException("A percentage value must be between 0 and 100: $percentage")
}
try、catch和finally:
Kotlin中方法声明中不必显示的指定函数throws可能抛出的异常,Kotlin 中并不区分受检查异常和未受检查异常,不用指定函数抛出的异常,可以处理也可以不处理。
// try、catch和finally
/**
* 读取文件中一行的内容,解析数字,抛异常
* Kotlin中方法声明中不必显示的指定函数throws可能抛出的异常,
* 需要知道Kotlin 中并不区分受检查异常和未受检查异常,不用指定函数抛出的异常,可以处理也可以不处理
*/
fun readNumber(reader: BufferedReader): Int? {
// 读取文件中一行的内容,解析数字
try {
val line = reader.readLine()
return Integer.parseInt(line)
} catch (e: NumberFormatException) {
e.printStackTrace()
// return null
} finally {
// finally的作用和java 一样
reader.close()
}
return null
}
try 作为表达式,可以把它的值赋值给一个变量 将final去掉:
注意:try catch finally 中总是需要用花括号把语句主体(就一句也需要)括起来,如果有多个表达式,那么最后一个表达式就是返回值
/**
* try 作为表达式,可以把它的值赋值给一个变量 将final去掉
*
* 并且try catch finally 中总是需要用花括号把语句主体(就一句也需要)括起来,
* 如果有多个表达式,那么最后一个表达式就是返回值
*/
fun readNumber2(reader: BufferedReader) {
// 读取文件中一行的内容,解析数字
val number = try {
// 第一条表达式
val test = 1
// 变为try表达式的值
Integer.parseInt(reader.readLine()) + test
} catch (e: NumberFormatException) {
return
}
println(number)
}
测试:
val reader = BufferedReader(StringReader("not a number"))
// 不会有任何输出,因为catch中return了
readNumber2(reader)
readNumber2 方法中将return语句放在了catch代码块中,因此该函数的执行在catch代码块之后就不会继续了。
如果想要继续执行后面的代码,catch子句也需要有一个值,它将是子句中最后一个表达式的值。
/**
* readNumber2 方法中将return语句放在了catch代码块中,因此该函数的执行在catch代码块之后就不会继续了。
* 如果想要继续执行后面的代码,catch子句也需要有一个值,它将是子句中最后一个表达式的值
*/
fun readNumber3(reader: BufferedReader) {
// 读取文件中一行的内容,解析数字
val number = try {
// 第一条表达式
val test = 1
// 变为try表达式的值
Integer.parseInt(reader.readLine()) + test
} catch (e: NumberFormatException) {
// 发生异常的时候直接赋值为null
null
}
// 发生异常的时候打印值为null
println(number)
}
到此,Kotlin 的基础差不多了,可以使用Kotlin进行开发了。
总结一下:
1、fun 关键字 用来声明函数。
2、val 关键字 用来声明只读变量。
3、var 关键字 用来声明可变变量。
4、字符串模板帮助你避免繁琐的字符串连接。在变量名称前加上 $ (美元符号)前缀或者用 ${ } 包围一个表达式,来把值注入到字符串中。
5、值对象类在Kotlin 中以简洁的方式表示。
6、熟悉的 if 现在是带返回值的表达式。
7、when 表达式类似于java中的switch但功能更强大。
8、在检查过变量具有某种类型之后不必显式地转换它的类型:编译器使用智能转换自动帮你完成。
9、for、while和do-while 循环与java类似,但for循环现在更加方便,特别是当你需要迭代map的时候,又或是迭代集合需要下标的时候。
10、简洁的语法1..10会自动创建一个区间。区间和数列允许Kotlin在for循环中使用统一的语法和同一套抽象机制,并且还可以使用 in 运算符和 !in 运算符来检查值是否属于某个区间。
11、Kotlin 中的异常处理和java 非常相似,除了Kotlin 不要求你声明函数可以抛出的异常。
说明一下:本文是按照《Kotlin in Action》这本书来进行学习的。