第二章:函数与变量
2.1 函数和变量
2.1.1 函数 fun
//普通函数
fun test(name: String){
}
//带返回值的函数
fun test0(name: String):Int{
return 1
}
//if是一个表达式
fun test1(a: Int,b:Int):Int{
return if (a>b) a else b
}
tip:语句和表达式
在Kotlin 中, if 是表达式,而不是语句。语句和表达式的区别在于,表达式有佳,并且能作为另一个表达式的一部分使用;而语句总是包围着它的代码块中的顶层元素,并且没有自己的值。在 Java 中,所有的控制结构都是语句而在 Kotlin 中,除了循环( for, do do/while )以外大多数控制结构都是表达式 这种结合控制结构和其他表达式的能力让你可以简明扼要地表示许多常见的模式,稍后你会在本书中看到这些内容另一方面, Java 中的赋值操作是表达式,在 Kotlin 中反而变成了语句有助于避免比较和赋值之间的混淆,而这种混淆是常见的错误来源
表达式函数体
如果函数写在花括号里,就说这个函数有代码块,如果直接返回了一个表达式,它就有表达式体
//表达式函数体,返回类型由类型推导完成
fun test2(a: Int, b: Int) = if (a > b) a else b
2.1.2变量
初始化
//变量初始化 自动推导类型
val name = "Bob"
val name1: String? = null
可变变量和不可变变量
val - 不可变引用,声明的变量不能在初始化之后再次赋值,对应java的final变量
var - 可变引用,声明的变量可以被改变
尽可能使用不可变引用来声明变量,使得程序更加接近函数式风格
2.2 1字符串模板
使用 $来引用变量
fun test(name: String) {
//字符串模板
val name = "test"
val names = mutableListOf<String>()
names.add(name)
println("name is $name")
println("names is ${names[0]}")
}
2.2.2类与属性
类:将数据和处理数据的代码封装成一个单一的实体
koltin中声明一个带属性的类
class Person(val name: String, val age: Int? = null)
在kotlin中属性完全替代了字段和访问器方法,在类中声明一个属性和声明一个变量是一样的,当声明属性的时候,就已经声明了对应的访问器 ,val 生成一个字段和get ,var生成一个字段和set get,声明后在java和kotlin中都是可访问的,这是默认的实现,还可以自定义访问器
自定义访问器
class Rectangle(val height: Int, val width: Int) {
val isRectangle: Boolean
get() {
return height == width
}
}
tip:一般来说如果描述的是类的特征,应该把它声明为属性
2.2.3源码布局,目录和包
一般来说,遵循java的目录和布局并根据包结构把源码文件放到目录中,但是一些小的类可以考虑放到一起
2.3 表示和处理选择,枚举和when
枚举类的使用
//基础的枚举类
enum class Color() {
RED, GREEN, BLUE
}
//带属性的枚举类
enum class ColorS(val r: Int, val g: Int, val b: Int) {
Red(255, 0, 0), Green(255, 0, 0), Blue(255, 255, 255);
//枚举类中有属性和方法时就需要添加分号隔开
fun rgb() = (r + g + b)
}
When
1.when关键字的使用,结合枚举类
fun getColorNum(colorS: ColorS) {
when (colorS) {
ColorS.Red -> 110
ColorS.Blue -> 120
ColorS.Green ->121
}
}
2.when结构比java中的switch强大很多,switch要求必须使用常量作为分支条件,when允许使用任何对象
fun setColor(color1: Color, color2: Color){
when(setOf(color1,color2)){
setOf(Color.RED,Color.BLUE) -> Color.GREEN
}
}
3.使用不带参数的when
//不带参数的when,分支条件就是任意的布尔表达式
fun mix(color1: Color, color2: Color){
when{
(color1 == Color.RED && color2 == Color.BLUE) -> Green
}
}
优点是不创建额外的对象,代价是难以理解
智能类型转换
is关键字
使用后不需要再手动判断类型,java的instanceOf还需要显示的加上类型转换
//智能转换只在变量经过is检查后不再发生变化情况下有效,必须是val属性,而且不能用自定义的访问器
fun eval(a: Any){
if (a is String){
println(a.length)
}
}
as 关键字
表示到特定类型的显示转换
While和for循环
//while和java的while是一样的
fun whileTest(num: Int){
while (num > 0){
//条件满足时触发
}
do {
//第一次会无条件执行,后续会判断条件
}while (num > 0)
}
区间和数列
区间本质上就是两个值之间的间隔,通常是数字,使用…运算符
//区间 ..代表包含
val oneToTen = 1..10
// 不包含
val oneToNine = 1 until 9
如果你可以迭代区间所有的值,这样的区间被称为数列
downto:用于创建递减区间
step:制定步长
//创建一个递减的步长为2的区间
val complexRange = 10 downTo 1 step 2
//结果为[10, 8, 6, 4, 2]
初始化并for输出map
val binaryReps = TreeMap<Char,String>()
fun forMap(){
for(c in 'A'..'F'){
val binary = Integer.toBinaryString(c.code)
binaryReps[c] = binary
}
for((letter,binary) in binaryReps){
println("$letter = $binary")
}
}
使用"in"或"!in"关键字来检查集合和区间的成员
fun isNum(){1 in 1..10}
fun isNotNum(){1 !in 1..10}
fun isEquals(){"hh" in setOf("hh", "ha")
2.4 koltin中的异常
与java不同的点在于,kotlin中throw结构是一个表达式,能作为另外一个表达式的一部分使用
//条件满足变量会初始化,不满足抛出异常,变量也不会初始化
val error =
if (1 in 1..10)
20
else
throw IllegalArgumentException("error")
使用try catch 和 finally
和java的区别
表达式和语句:
在Kotlin中,throw是一个表达式,可以用于赋值,例如val result = if (condition) value else throw Exception(“Error”)。
在Java中,throw是一个语句,不能像Kotlin那样直接用于赋值。
检查异常:
在Java中,编译器要求你必须捕获或声明可能抛出的检查异常。
在Kotlin中,没有检查异常的概念,所有异常都是非受检异常,你不需要在函数签名中声明可能抛出的异常。
类型推断:
在Kotlin中,由于throw是表达式,可以通过类型推断确定表达式的类型。
在Java中,throw是一个语句,不会有类型推断的问题。