1、函数和变量
1.1 函数
fun max(a:Int,b:Int):Int{
return if(a>b) a else b
}
>>>println(max(1,2))
我们以上面的代码为例:函数的声明以关键字fun开始,函数名称紧随其后。
本例中函数的基本结构为
注意:在kotlin中,if是表达式,而不是语句。语句和表达式的区别在于,表达式有值,并且能作为另一个表达式的一部分使用;而语句总是包围着它的代码块的顶层元素,并没有自己的值。例子中if表达式和java中的三元运算符相似:(a>b)?a:b.
表达式函数体
在书写上我们可以让上例变得更简单
因为签名的函数它的函数体是由单个表达式构成的,所有可以写成这样的形式:
fun max(a:Int,b:Int):Int=if(a>b)a else b
这种形式的函数就叫做表达式体的函数。
1.2 变量
kotlin中变量的声明和java不一样。
假如你直接为变量名赋值的话不需要指定变量的类型:
val m="I love you"
如果你没有为变量名赋值的话需要指定变量的类型:
val m:String
m="I love you"
声明变量的关键字有两个:
val——不可变引用。对应于java的final变量
var——可变引用。对应于java中的普通变量(不用final修饰)
1.3 字符串模板
fun main(args:Array<String>){
val name=if(args.size>0) args[0] else "kotlin"
println("hello,$name")
}
$字符不仅可以引用简单的变量名称,还可以引用表达式,不过要把表达式用{}括起来。
${if(args.size>0) args[0] else "someone"}
像上面这个样子的:字符串可以包含模板表达式,即一小段代码,以美元字符$开头被称为字符串模板。
2、类和属性
2.1 属性
class Person{
val name:String, //只读属性,相当于java中声明了一个变量并提供了一个getter方法
var isMarried:Boolean//可写属性,相当于java中声明了一个变量并提供了getter,setter方法
}
Person类的使用
val person=Person("Bob",true)
println(person.name)
println(person.isMarried)
运行结果:
Bob
true
2.2 自定义访问器
声明一个矩形,它能自己判断自己是否是正方形。这样的就是自定义访问器。
class Rectangle(val height:Int,val Int){
val isSquare:Boolean
get(){
return height==width
}
}
像上面的代码属性isSquare不需要字段来保存它的值。它的值是每次访问属性的时候计算出来的。
get()方法也可以这样写:get()=height==width
调用的时候
val rectangle=Rectangle(41,43)
println(rectangle.isSquare)
false
3、枚举和"when"
3.1 声明枚举类
声明一个简单的枚举类
enum class Color{
Red,Green,Yellow
}
声明一个带属性的枚举类
enum class Color(val r:Int,val g:Int,val y:Int){
Red(255,0,0),Green(0,255,0),Yello(75,0,0);//kotlin中唯一需要使用分号的地方
fun rgy()=(r*24+g)*23+y //给枚举类定义一个方法
}
println(Color.Yello.rgy())
3.2 使用"when"处理枚举类
kotlin中的"when"相当于java中的"switch"
fun getMNEMONIC(color:Color)=when(color){
Color.Red->"I"
Color.Green->"Love"
Color.Yello->"You"
}
println(getMNEMONIC(Color.Green))
结果:Love
在这里when它的作用和switch一样,同时它也是一个有返回值的表达式。
在when结构中不需要为每个分支写上break语句。可以把多个值合并到同一分支,各个值用逗号隔开
Color.Red,Color.Green->"I'm cold"
3.3 在"when"结构中使用任意对象
java中的switch要求必须使用常量作为分支条件,when允许使用任何对象。
调色板
fun mix(c1:Color,c2:Color)=when(setOf(c1,c2)){
setOf(Red,Yello)->ORANGE
setOf(Red,Green)->BLUE
else->throw Exception("Dirty color")
}
3.4 使用不带参数的"when"
fun mixOptimized(c1:Color,c2:Color)=when{
(c1==Red&&c2==Yello)||(c1==Yello&&c2==Red)->ORANGE
(c1==Red&&c2==Green)||(c1==Green&&c2==Red)->BLUE
else->throw Exception("Dirty color")
}
3.4中的代码和3.3中的代码实现效果是一样的,不过3.3中代码每次调用setOf()函数都会创建Set实例,调用频繁很容易参数垃圾对象。
4、迭代事物:"while"循环和"for"循环
4.1 "while"循环
kotlin中的"while"循环、do-while循环和java中相应的循环没有什么区别。
4.2 迭代数字:区间和数列
区间:区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值。使用...运算符来表示区间
val oneToTen=1..10
ClosedRange的子类,IntRange最常用
0..100表示[0,100]
0 until 100表示[0,100)
数列:能迭代区间中所有的值,这样的区间被称作数列。
for...in循环的最常见的场景是迭代集合
for(i in 1..100){
println(i)
}
4.3 迭代map
val binaryReps=TreeMap<Char,String>()
for(c in 'A'..'F'){
val binary=Integer.toBinaryString(c.toInt())//把ASCII码转换为二进制
binaryReps[c]=binary//根据键c把值存储到map中 等价于java版binaryReps.put(c,binary)
}
for((letter,binary)in binaryReps){
println("$letter=$binary")
}
可以用展开语法在迭代集合的同时跟踪当前项下标。不需要像上面那样创建单独的变量c来存储下标。
val list=arrayListOf("10","11","1001")
for((index,element)in list.withIndex()){//迭代集合时使用下标
println("$index:$element")
}
4.4 "in"检查集合和区间的成员
我们通常用in运算符来检查一个值是否在区间中,或者它的逆运算!in来检查这个值是否不在区间中。
fun isLetter(c:Char)=c in 'a'..'z'||c in 'A'..'Z'
fun isNotDigit(c:Char)=c !in '0'..'9'
>>>pirntln(isLetter('q'))
true
>>> println(isNotDigit('x'))
true
5、kotlin中的异常
5.1 "try""catch"和"finally"
和java一样,使用带有catch和fianally字句的try结构来处理异常。
fun readNumber(reader:BufferedReader):Int?{ //不必显式地指定这个函数可能抛出的异常
try{
val line=reader.readLine()
return Interger.parseInt(line)
}catch(e:NumberFormatEcxeption){
return null
}finally{
reader.close()
}
}
和java最大的区别就是throws子句没有出现在代码中,如果是java代码的话会显式地在函数声明后写上thrwos IOException.
5.2 "try"作为表达式
fun readNumber(reader:BufferedReader){
val number=try{
val line=reader.readLine()
return Interger.parseInt(line) //没有异常的时候返回这个值
}catch(e:NumberFormatEcxeption){
return null //发生异常的情况下使用null
}
println(number)
}
本系列博客参考《kotlin实战》