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代码块最后一个表达式就是结果。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值