Kotlin实战——Kotlin基础
Posted ABded
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin实战——Kotlin基础相关的知识,希望对你有一定的参考价值。
文章目录
1.基本要素:函数和变量
1.1 函数
首先我们来定义一个无返回值的函数
fun main(args:Array<String>)
println("Hello,world!")
接下来我们再来看看带返回值的函数是如何定义的
fun max(a:Int,b:Int):Int
return if(a>b) a else b
至此我们就可以来总结一下在kotlin中定义函数的一般方式了:函数的声明以关键字fun开始,函数名紧跟其后,接下来是参数列表。参数列表的后面跟着返回类型,它们之间用一个冒号隔开。
上述代码中还有一点值得我们注意一下:在kotlin中if是表达式而并非语句,语句和表达式的区别在于,表达式有值并且可以作为另一个表达式的一部分,而语句则没有自己的值。(事实上在kotlin中除了循环(for,do和do/while)外大多数的控制结构都是表达式,因此kotlin可以简明扼要的表示许多常见的模式)
事实上因为上述函数的函数体是由单个表达式构成的,所以我们可以用更加简洁的方式来表示它。
fun max(a:Int,b:Int):Int=if(a>b) a else b//这种类型的函数被称作表达式体的函数
1.2变量
在kotlin中变量是以关键字开始的,然后是变量名称,最后可以加上类型(不加也可以)。
val question="something"(可以在初始化时直接赋值以省略变量类型)
val answer=42
val answer02:Int(注:如果初始化时不直接赋值,那么就必须显式的为变量加上类型)
变量之前的关键字共有两种:
- val:不可变引用(相当于java中的final变量)
- var:可变引用
注:默认情况下,应该尽可能的使用val关键字来声明所有的kotlin变量,仅在必要时换成var。
关于val我们还要注意的是,尽管val引用自身是不可变的,但它指向的对象可能是可变的。(不可变变量不可变,不可变对象指代的东西可变)例如,下面的这段代码是完全有效的:
val languages= arrayListOf("java")
languages.add("Kotlin")
1.3更简单的字符串格式化:字符串模板
首先我们来看看怎样使用字符串模板
fun main(args:Array<String>)
val name=if(args.size>0) args[0] else "Kotlin"
println("Hello,$name!")//$name即为字符串模板
现在我们来总结一下字符串模板的功能:可以在字符串字面值中引用局部变量,即取出不同类型变量下的字符串值。
事实上我们还可以引用更复杂的表达式,而不是仅限于简单的变量名称,只需要把表达式用花括号括起来:
fun main(args:Array<String>)
if(args.size>0)
println("Hello,$args[0]!")
2.类和属性
我们先来看一下最简单的一种对象——值对象(只有数据没有其它代码)的定义方法
class Person(val name:String)
2.1属性
在java中,往往我们在定义类中的变量时都要为其实现访问器,字段和其访问器的组合被称作属性。而在kotlin中,声明属性的方法和声明变量一样:使用val和var关键字,声明成val的属性是只读的,而var属性是可变的。(本质上是kotlin的编译器帮助我们自动实现了变量的访问器)
class Person(
val name:String, //只读属性:生成一个字段和一个简单的getter
var isMarried:Boolean//可写属性:一个字段,一个getter和一个setter
)
注:如果有需要,我们可以声明自定义的访问器,使用不同的逻辑来计算和更新属性的值。
由于我们并没有定义属性的访问器,所以我们现在可以直接饮用属性了,而不是调用getter。
fun main(args:Array<String>)
val person=Person("Bob",14)
println(person.name)//本质上依然是调用了getter方法
2.2自定义访问器
代码示例
class Rectangle(val height:Int,val width:Int)
val isSquare:Boolean//该属性不需要字段来保存它的值,它只有一个自定义实现的getter,它的值是每次访问属性的时候计算出来的
get()
return height==width
3.表示和处理选择:枚举和“when”
3.1声明枚举类
我们先给出一个简单的枚举类的定义
enum class Color
RED,ORANGE,YELLOW,GREEN,BLUE,INDIGO,VIOLET
我们只需要用enum关键字来修饰一个类,即可让它成为枚举类
接下来,我们给枚举类声明属性和方法
enum class Color(val r:Int,val g:Int,val b:Int)
RED(255,0,0),ORANGE(255,165,0),
YELLOW(255,255,0),GREEN(0,255,0),BLUE(0,0,255),
INDIGO(75,0,130),VIOLET(238,130,238);
fun rgb()=(r*256+g)*256+b
注:当声明每个枚举常量的时候,必须提供该常量的属性值;如果要在枚举类中定义任何方法,就要使用分号把枚举常量列表和方法定义分开。
3.2使用“when”处理枚举类
我们先来看一个when的实际用法(和if相似,when也是一个表达式)
fun getMnemonic(color: Color)=//直接返回一个when表达式
when(color)//如果颜色和枚举常量相等就返回对应的字符串
Color.RED->"Richard"
Color.ORANGE->"Of"
Color.YELLOW->"York"
Color.GREEN->"Gave"
Color.BLUE->"Battle"
Color.INDIGO->"In"
Color.VIOLET->"Vain"
实际上,我们还可以在一个when分支上合并多个选项
fun getWarmth(color: Color)=when(color)
Color.RED,Color.ORANGE,Color.YELLOW->"warm"
Color.GREEN->"neutral"
Color.BLUE,Color.INDIGO,Color.VIOLET->"clod"
3.3在“when”结构中使用任意对象
我们先来展示用set来做when的分支条件
fun mix(c1:Color,c2:Color)=
when(setOf(c1,c2))//setOf函数用于创建一个Set
setOf(Color.RED,Color.YELLOW)->Color.ORANGE
setOf(Color.YELLOW,Color.BLUE)->Color.GREEN
setOf(Color.BLUE,Color.VIOLET)->Color.INDIGO
else->throw Exception("Dirty color")
接下来,我们就来总结一下when的作用:when表达式把它的实参依次和所有分支匹配,直到某个分支满足条件。
3.4使用不带参数的“when”
代码示例:
when
(c1==Color.RED&&c2==Color.YELLOW) || (c1==Color.YELLOW&&c2==Color.RED)->Color.ORANGE
(c1==Color.YELLOW&&c2==Color.BLUE) || (c1==Color.BLUE&&c2==Color.YELLOW)->Color.GREEN
(c1==Color.VIOLET&&c2==Color.BLUE) || (c1==Color.BLUE&&c2==Color.VIOLET)->Color.INDIGO
else->throw Exception("Dirty color")
说明:如果没有给when表达式提供参数,分支条件就是任意的布尔表达式。
3.5智能转换:合并类型检查和转换
接下来我们来介绍kotlin中的新特性——智能转换
假设我们现在有以下数据类型
interface Expr
class Num(val value:Int) :Expr
class Sum(val left:Expr,val right:Expr) :Expr
然后我们定义一个函数,根据对象属于不同的类分别进行不同的操作
//熟悉java的同学应该清楚,当我们判断一个对象属于一个类之后,倘若要把其当作该类来访问类中的成员时我们还需要进行类型转换,就像下面的代码
fun eval(e:Expr):Int=
if(e is Num)
e as Num//将e转换为Num类
e.value
else if(e is Sum)
e as Sum//将e转换为Sum类
eval(e.left)+ eval(e.right)
else
throw IllegalArgumentException("Unknown expression")
实际上在kotlin中我们完全可以把上述代码改写成下面的代码(不需要再显式的进行类型转换了)
fun eval(e:Expr):Int=
if(e is Num)
e.value
else if(e is Sum)
eval(e.left)+ eval(e.right)
else
throw IllegalArgumentException("Unknown expression")
现在我们就来总接一下kotlin中的智能转换:如果你检查过一个变量是某种类型,后面就不再需要转换它,可以把它当作你检查过的类型使用。事实上编译器为你执行了类型转换,我们把这种行为称为只能转换。
3.6重构:用“when”代替“if”
when表达式并不仅限于检查值是否相等,它还可以用来检查when实参值的类型
用when重写上述代码:
fun eval(e:Expr):Int=
when(e)
is Num->
e.value
is Sum->
eval(e.right)+ eval(e.left)
else->throw IllegalArgumentException("Unknown expression")
在kotlin中when可以胜任大多数if的功能,而官方也是更推荐我们在程序编写时使用when来代替if
3.7代码块作为“if”和“when”的分支
if和when都可以使用代码块作为分支体。而在这种情况下,代码块中的最后一个表达式就是结果。
代码示例:
fun eval(e:Expr):Int=
when(e)
is Num->
println("num:$e.value")
e.value//如果e的类型是Num就会返回它
is Sum->
println("sum:$eval(e.left)+$eval(e.right)")
eval(e.right)+ eval(e.left)//如果e的类型是Sum就会返回它
else->throw IllegalArgumentException("Unknown expression")
总结:“代码块中最后的表达式就是结果”,在所有使用代码块并期望得到一个结果的地方成立。
4.迭代事物:“while”循环和“for”循环
4.1“while”循环
kotlin有while循环和do-while循环,它们的语法和java中相应的循环没什么区别
代码示例:
while(condition)//当condition为true时执行循环体
//...
do
//...
while (condition)//循环体第一次会无条件地执行。此后,当condition为true时才执行
4.2迭代数字:区间和数列
kotlin中没有常规的java for循环。在这种循环中,先初始化变量,在循环的每一步更新它的值,并在值满足某个限制条件时退出循环。为了替代这种最常见的循环用法,kotlin使用了区间的概念。
区间:本质上就是两个值之间的间隔,这两个值通常是数字,一个起始值,一个结束值。使用. .运算符来表示区间(注:kotlin中区间的值是闭合的,也就是说结束值也是区间的一部分)
代码示例:
for(i in 1..100)
print(i)
我们可以定义更多的规则,来让迭代区间时只迭代我们需要的值
代码示例:
for (i in 100 downTo 1 step 2)//在这个例子中100 downTo 1是递减序列(步长为-1),然后step把步长的绝对值变成了2,但方向保持不变(也就是说最终步长为-2)
print(i)
另外,熟悉其它语言编程的同学可能更喜欢结束指定值为半闭合区间(也就是迭代区间不包含结束指定值),在kotlin中可以通过until关键字实现
代码示例:
for (i in 1 until 100)
print(i)
4.3迭代map
接下来我们来看看怎样利用for循环迭代map集合
代码示例:
val binaryReps=TreeMap<Char,String>()
for(c in 'A'..'F')//..语法不仅可以创建数字区间,还可以创建字符区间
val binary=Integer.toBinaryString(c.toInt())
binaryReps[c]=binary
for((letter,binary) in binaryReps)
println("$letter = $binary")
总结:for循环允许展开迭代中的集合的元素,把展开的结果存储到独立的变量中。(在这个例子中展开的是map的键值对集合,并把其存储到letter和binary中)
4.4使用“in”检查集合和区间的成员
使用 in 运算符来检查一个值是否在区间中,或者它的逆运算,!in,来检查这个值是否不在区间中。
代码示例:
fun isLetter(c:Char) = c in 'a'..'z'||c in 'A'..'Z'//判断c是否为字母
fun isNotDigit(c:Char) = c !in '0'..'9'//判断c是否为数字
另外,in运算符和!in也适用于when表达式
代码示例:
fun recognize(c:Char)=when(c)
in '0'..'9'->"It`s a digit"
in 'a'..'z',in 'A'..'Z'->"It`s a letter"
else ->"I don`t know"
另外,in检查同样适用于集合,这里就不举例赘述了。
5.Kotlin中的异常
Kotlin中异常处理语句的基本形式和java类似,
代码示例:
val percentage=101
if(percentage !in 0..100)
throw IllegalArgumentException("A percentage value must be between 0 and 100:$percentage")
注:这里的throw结构是一个表达式,能作为另一个表达式的一部分使用。
5.1“try” “catch” 和 “finally”
熟悉Java的同学应该知道,这三个关键字是经常用来处理异常用的,同样在kotlin中也是可以利用这三个关键字来处理异常的
代码示例:
fun readNumber(reader: BufferedReader):Int?//不必显示的指定这个函数可能抛出的异常
try
val line=reader.readLine()
return Integer.parseInt(line)
catch (e:NumberFormatException)
return null
finally
reader.close()
注:在kotlin中这样处理异常与在java中最大的区别在于,不必显示的指定这个函数可能抛出的异常。
5.2“try”作为表达式
try关键字同样也是一个表达式,接下来我们就来利用这一特点来修改上述代码,使其更加的简介
代码示例:
fun readNumber(reader: BufferedReader)
val number = try
Integer.parseInt(reader.readLine())//没有异常发生时使用这个值
catch (e:NumberFormatException)
null//发生异常的情况下使用null
println(number)
总结:try代码块执行一切正常,代码块中最后一个表达式就是结果。如果捕获到了一个异常,相应catch代码块最后一个表达式就是结果。
以上是关于Kotlin实战——Kotlin基础的主要内容,如果未能解决你的问题,请参考以下文章