Kotlin | 2.Kotlin基础
2019.03.24
JinBeen
Kotlin
 热度
℃
上篇:《Kotlin | 1.定义和目的》
- 声明函数、变量、类、枚举以及类型
- Kotlin中的控制结构
- 智能转换
- 抛出和处理异常
函数学习
函数和变量
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| * 求最大值 * if是表达式而不是语句,表达式有值,语句没有。 * java中所有的控制结构都是语句 * kotlin中除了循环以外大多数控制结构都是表达式 */ private fun max(a: Int, b: Int): Int { return if (a > b) a else b } * 如果函数体写在花括号中,我们说这个函数有代码块体。 * 如果直接返回了一个表达式体,他就有表达式体。 */ fun max2(a: Int, b: Int): Int = if (a > b) a else b
|
变量
可变变量和不可变变量
- val - 不可变引用。 相当于Java的final变量。
- var - 可变引用。 普通的Java变量。
在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件使用不同的值来初始化它:
1 2 3 4 5 6 7
| val message:String if (CanPerformOperation()){ message = "Success" } else{ message = "Failed" }
|
注意:尽管val引用自身是不可变的,但是它指向的对象可能是可变的。例如:
1 2
| val languages = arrayListOf("Java") languages.add("Kotlin")
|
错误:类型不匹配
1 2
| var answer = 42 answer = "no answer"
|
字符串模板
1 2 3 4 5 6 7
| var a1 = 1 val s1 = "a is $a1" a1 = 3 val s2 = "${s1.replace("is", "was")},but no is $a1" Log.e("s2", s2)
|
和许多脚本语言一样,只需要在变量名称前加上 $ ,就可以在字符串字面值中引用局部变量。
引用”$”需要转义“\$”
类和属性
类
在Kotlin中,public是默认的可见性,所以你能省略它。
1 2 3 4 5 6 7 8
| public class Person { private final String name; public Person(String name) { this.name = name; } }
|
—>
1
| class Person(private val name: String)
|
属性
1 2 3 4 5 6 7 8 9 10 11 12
| class PersonProperty { val name: String = "kotlin_hahaha" var isMarried: Boolean = false fun set() { isMarried = true } }
|
自定义访问器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| /** * Created by jingbin on 2018/11/18. * 自定义访问器 * 也可以使用函数返回,实现和性能没有差别,唯一的差别是可读性 * 通常来说: * 如果描述的是类的特征(属性),应该把它声明成属性。 */ class Rectangle(val height: Int, val width: Int) { // 函数表达式 可以赋值 val isSquare: Boolean // 声明属性的getter get() { return height == width } }
|
Kotlin源码布局:目录和包
1.把类和函数的声明放在包中,可以同级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Rectangle(val height: Int, val width: Int) { val isSquare: Boolean get() { return height == width } } fun createRandomRectangle(): Rectangle { val random = Random() return Rectangle(random.nextInt(), random.nextInt()) }
|
Kotlin不区分导入的是类还是函数,而且,它允许使用import关键字导入任何种类的声明。可以直接导入顶层函数的名称。
2.导入其他包中的函数
1 2 3 4
| import com.kotlin.jingbin.kotlinapp.classproperty.createRandomRectangle LogUtil.e(createRandomRectangle().isSquare)
|
包层级和java类似。
表示和处理选择: 枚举和”when”
when结构,java中switch结构的替代品,但是更强大。智能转换。
枚举
1.声明简单的枚举类
1 2 3
| enum class SimpleColor { RED, ORANGE }
|
2.声明一个带属性的枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| enum class Color( val r: Int, val g: Int, val b: Int) { RED(255, 0, 0), ORANGE(255, 165, 0), WELLOW(255, 255, 0), GREEN(0, 255, 0), BULE(0, 0, 255), INDIGO(75, 0, 130), VIILET(238, 130, 238); fun rgb() = (r * 256 + g) * 256 + b }
|
3.使用“when”处理枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| * 使用when处理枚举类: * 直接返回一个“when"表达式 */ fun getMnemonic(color: Color) = { when (color) { RED -> "Richard" ORANGE -> "Of" WELLOW -> "Haha" BULE, GREEN -> "望穿" VIILET, INDIGO -> "秋水" } }
|
when
1、在 when 结构中使用任意对象
1 2 3 4 5 6 7 8 9 10
| fun mix(c1: Color, c2: Color) = { when (setOf(c1, c2)) { setOf(Color.RED, Color.YELLOW) -> Color.ORANGE setOf(Color.BLUE, Color.YELLOW) -> Color.GREEN setOf(Color.BLUE, Color.VIOLET) -> Color.INDIGO else -> throw Exception("Dirty color") } }
|
2、不带参数的 when
1 2 3 4 5 6 7 8 9 10
| fun minOptimized(c1: Color, c2: Color) = { when { (c1 == Color.RED && c2 == Color.YELLOW) || (c2 == Color.RED && c1 == Color.YELLOW) -> Color.ORANGE (c1 == Color.BLUE && c2 == Color.YELLOW) || (c2 == Color.BLUE && c1 == Color.YELLOW) -> Color.GREEN (c1 == Color.BLUE && c2 == Color.VIOLET) || (c2 == Color.BLUE && c1 == Color.VIOLET) -> Color.INDIGO else -> throw Exception("Dirty color") } }
|
3、智能转换:合并类型检查和转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| interface Expr class Num(val value: Int) : Expr class Sum(val left: Expr, val right: Expr) : Expr * 3.2 使用 if 层叠对表达式求值 * 在 Kotlin 中,如果你检查过一个变量是某种类型,后面就不再需要转换它,可以就把它当作你检查过的类型使用。 * 事实上编译器为你执行了类型转换,我们把这种行为称为智能转换。 * */ fun eval(e: Expr): Int { if (e is Num) { val num = e as Num return num.value } if (e is Sum) { return eval(e.left) + eval(e.right) } throw IllegalAccessException("Unknown expression")
|
4、重构:用“when”代替“if”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| * Kotlin 中没有三元运算符,因为if有返回值 * 意味着: 可以用表达式语法重写eval函数,去掉return语句和花括号,使用if表达式作为函数体 */ fun eval2(e: Expr): Int = if (e is Num) { e.value } else if (e is Sum) { eval2(e.right) + eval2(e.left) } else { throw IllegalAccessException("Unknown expression") } fun eval3(e: Expr): Int = when (e) { is Num -> e.value is Sum -> eval3(e.right) + eval3(e.left) else -> throw IllegalAccessException("Unknown expression") }
|
5、代码块作为 “if” 和 “when” 的分支
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| * 一个函数要么具有不是代码块的表达式函数体, * 要么具有包含显示return语句的代码块函数体 */ fun evalWithLogging(e: Expr): Int = when (e) { is Num -> { LogUtil.e("num: ${e.value}") e.value } is Sum -> { val left = this.evalWithLogging(e.left) val right = this.evalWithLogging(e.right) LogUtil.e("Sum: $left + $right") left + right } else -> throw IllegalAccessException("Unknown expression") }
|
迭代事物: “when”循环和“for”循环
1、“while” 循环
Kotlin 有 while 循环和 do-while 循环,他们的语法和Java中相应的循环没有什么区别
2、迭代数字:区间和数列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| * 区间:区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值。 * 使用 .. 运算符来表示区间 * 数列:你能用整数区间做的最基本的事情就是循环迭代其中所有的值。 * 如果你能迭代区间中所有的值,这样的区间被称作数列。 * */ val oneToTen = 1..10 fun fizzBuzz(i: Int) = when { i % 15 == 0 -> "FizzBuzz" i % 3 == 0 -> "Fizz" i % 5 == 0 -> "Buzz" else -> "$i" } for (i in 1..100) { } for (i in 100 downTo 0 step 2) { LogUtil.e(fizzBuzz(i)) }
|
3、迭代map
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| val binaryReps = TreeMap<Char, String>() for (c in 'A'..'F') { val binaryString = Integer.toBinaryString(c.toInt()) binaryReps[c] = binaryString } for ((letter, binary) in binaryReps) { LogUtil.e("$letter = $binary") } val list = arrayListOf("10", "11", "1001") for ((index, element) in list.withIndex()) { LogUtil.e("$index = $element") }
|
4、使用 “in” 检查集合和区间的成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z' fun isNoDigitic(c: Char) = c !in '0'..'9' fun recognize(c: Char) = when (c) { in '0'..'9' -> "In's a digit!" in 'a'..'z', in 'A'..'Z' -> "In's a letter!" else -> "I don't know.." } ``` ### Kotlin中的异常 ```kotlin val percentage = 0 if (percentage !in 0..100) { throw IllegalAccessException("A percentage value must be between 0 and 100: $percentage") } * 和所有其他类一样,不必使用 new 关键字来创建异常实例。 * 和java不同的是,Kotlin中throw结构是一个表达式,能作为另一个表达式的一部分使用: */ val number = 8 val percentage2 = if (number in 0..100) { number } else { throw IllegalAccessException("A percentage value must be between 0 and 100: $percentage") } val bufferedReader = BufferedReader(StringReader("239"))
|
1、try catch 和 finally
1 2 3 4 5 6 7 8 9 10 11 12 13
| fun readNumber(reader: BufferedReader): Int? { try { val line = reader.readLine() return Integer.parseInt(line) } catch (e: NumberFormatException) { return null } finally { reader.close() } }
|
2、try 作为表达式
1 2 3 4 5 6 7 8 9 10
| fun readNumber2(reader: BufferedReader) { val number = try { Integer.parseInt(reader.readLine()) } catch (e: NumberFormatException) { null } }
|
总结
- fun 关键字用来声明函数。Val关键字和var关键字分别用来声明只读变量和可变变量。
- 字符串模板帮组你避免繁琐的字符串拼接。在变量名称前加上 $ 前缀或者用 ${} 包围一个表达式,来把值注入到字符串中。
- 值对象类在Kotlin中以简洁的方式表示。
- 熟悉的if现在是带返回值的表达式。
- when表达式类似于Java中的switch但功能更强大。
- 在检查过变量具有某种类型之后不必显示地转换它的类型:编译器使用智能转换字段帮你完成。
- for、while、和 do-while 循环与java类似,但是for循环现在更加方便,特别是当你需要迭代map的时候,又或是迭代集合需要下标的时候。
- 简洁的语法 1..5 会创建一个区间。区间和数列允许Kotlin在for循环中使用统一的语法和同一套抽象机制,并且还可以使用in运算符和!in运算符来检查值是否属于某个区间。
- Kotlin中的异常处理和java非常相似,除了Kotlin不要求你声明函数可以抛出异常。