本文是对<<Kotlin in Action>>
的学习笔记,若是须要运行相应的代码能够访问在线环境 try.kotlinlang.org,这部分的思惟导图为: java
在Kotlin
中,函数的基本结构由四个部分构成:数组
函数的声明以关键字 fun 开始,函数名称 紧随其后,接下来是括号括起来的 参数列表,参数列表的后面跟着 返回类型,返回类型和参数列表之间用冒号隔开,最后是函数体。函数
下面是一个比较大小的函数例子,上面谈到的四个部分构成如图中标注所示: 学习
在上面的例子中,if
是表达式,而不是语句,表达式和语句的区别在于:3d
在Java
中,全部的控制结构都是语句,而在Kotlin
中,除了for
、do
和do/while
之外大多数控制结构都是表达式。code
当函数体是由单个表达式构成时,能够用这个表达式做为完整的函数体,而且去掉花括号和return
语句,上面的例子就是这种状况,所以能够改写为: cdn
对于 表达式体函数,能够省略返回类型,由于编译器会分析做为函数体的表达式,并把它的类型做为函数的返回类型,这种分析称为 类型推导。可是对于有返回值的 代码块体函数,必须显示地写出返回类型和return
语句。对象
上面的例子能够简化为: blog
在Kotlin
中,变量的声明以关键字val/var
开始,而后是变量名称,最后能够加上类型(不加也能够),这里分为两种状况:递归
Int
和Double
类型:
声明变量的关键字有两个:
使用val
声明的变量不能在初始化以后再次赋值,它对应的是Java
的final
变量。 默认状况下,应该尽量地使用val
关键字来声明全部的Kotlin
变量。在定义了val
变量的代码块执行期间,val
变量只能进行惟一一次初始化,可是,若是编译器能确保惟一一条初始化语句会被执行,能够根据条件使用不一样的值来初始化它。
这种变量的值能够改变,可是它的类型倒是改变不了的。
Kotlin
能够在字符串字面值中引用局部变量,只须要在变量名称前面加上字符$
。
$
,须要对它进行转义。
类的概念就是把数据和处理数据的代码封装成一个单一的实体,在Java
中,数据存储在字段中,而且一般是私有的。若是想让类的使用者访问到数据得提供访问方法,即getter/setter
。
在Java
中,字段和其访问器的组合经常被叫做属性。在Kotlin
中,属性是头等的语言特性,彻底 替代了字段和访问器方法。在类中声明一个属性和声明一个变量同样:使用val/var
关键字,前者是只读的,然后者是可变的。
当声明属性的时候,就声明了对应的访问器(只读属性有一个gettter
,而可变属性则有getter/setter
),例以下面的例子,声明了只读的name
属性,可变的isMarried
属性,其赋值和读取的方法以下所示:
假设声明一个矩形,它能判断本身是不是正方形,那么就不须要一个单独的字段来存储这个信息,此时咱们能够写一个自定义的访问器:用val
开头做为声明,紧跟着的是属性的名称和类型,接下来是get()
关键字,最后是一个函数体。
Kotlin
中包的概念和Java
相似,每一个kotlin
文件都能以一个package
语句开头,而文件中定义的全部声明(类、函数及属性)都会被放到这个包中。import
关键字。kotlin
不区分导入的是类仍是函数,并且,它容许使用import
关键字导入任何种类的声明,能够直接导入顶层函数的名称,也能够在包名称后加上.*
来导入特定包中定义的全部声明。Java
中,要把类放到和包结构相匹配的文件与目录结构中,而在kotlin
中,能够把多个package
声明不相同的类放在同一个文件夹中。声明枚举类时,enum
是一个所谓的软关键字,只有当它出如今class
前面时才有特殊的意义,在其余地方能够当作普通名称使用。而class
仍然是一个关键字,下面是一个枚举类的声明:
如下是一个带属性的枚举类:
when
是一个有返回值的表达式,所以,做为表达式函数体,它能够去掉花括号和return
语句,并省略返回类型的声明。
下面是一个经过when
处理枚举类的例子,它和Java
中的switch
语句相似,根据when
中Color
的值走到对应的分支,除此以外,咱们能够把多个值用逗号间隔,合并到同一个分支:
在Java
中,和when
相似的switch
语句要求必须使用常量(枚举常量、字符串或者数字字面值)做为 分支条件,而when
容许使用任何对象,咱们使用一个函数来混合两种颜色。下面例子中用到的setOf
是由Kotlin
标准函数库提供的,它能够建立出一个Set
,而且会包含全部指定为函数实参的对象,只要两个set
中包含同样的条目,它们就是相等的,集合的条目顺序并不重要。
when
表达式提供参数,这样分支条件就是任意的布尔表达时,这种写法的优势是不会建立额外的对象,但代价是它更难理解。
在kotlin
中,判断一个变量是不是某种类型须要使用is
关键字,它和Java
当中的instanceOf
类似。
Java
中,在检查完后还须要显示地加上类型转换。kotlin
中,若是你检查过一个变量是某种类型,后面就不须要再转换它,能够把它当作你检查过的类型来使用。咱们用下面这个例子,Num
和Sum
都实现了Expr
接口,经过is
判断它的类型,完成递归求和。能够看到,在is
判断以后,再也不须要转换成Num
或Sum
,就能够直接访问该类的成员变量。
智能转换 只在变量通过is
检查且以后再也不发生变化 的状况下有效,当你对一个类的属性进行智能转换的时候,这个属性必须是一个val
属性,并且不能有自定义的访问器,不然,每次对属性的访问是否都能返回一样的值将无从验证。
if
和when
均可以使用代码块做为分支体,这种状况下,代码块中的最后一个表达式就是结果,这个规则在全部使用代码块并指望获得一个结果的地方成立。一样的规则对try
主体和catch
子句也有效。
kotlin
和Java
同样,有while
循环和do-while
循环,它们的语法和Java
中相应的循环彻底一致。
在Java
当中,对于循环的处理方式为:先初始化变量,在循环的每一步更新它的值,并在值知足某个限制条件时退出循环。
而在Kotlin
中,为了替代常见的循环用法,使用了 区间 的概念,其本质上就是两个值之间的间隔,这两个值一般是数字:一个起始值,一个结束值。使用..
运算符来表示区间,而结束值始终是区间的一部分。
downTo
、
step
和
until
等用于区间的语法,用于进行循环操做,例以下面的例子
downTo
用于递减到指定的值,而
step
则指定步长:
until
则可使迭代不包含指定的结束值,例以下面这样:
这里咱们用到了TreeMap
,在更新map
时,咱们能够像使用数组同样,只不过下标变成了key
值:
下面的例子展现了for
容许容许展开迭代中的集合的元素,把展开的结果存储到了两个独立的变量中:letter
是键、binary
是值:
使用in
运算符来检查一个值是否在区间中,或者它的逆运算!in
来检查这个值是否不在区间中,区间不只限于字符,假若有一个支持实例比较操做的任意类(实现了java.lang.Comparable
接口),就能建立这种类型的对象的区间。
kotlin
的异常处理和Java
以及其余许多语言的处理方式相似:一个函数能够正常结束,也能够在出现错误的状况下抛出异常。方法的调用者能捕获到这个异常并处理它;若是没有处理,异常会沿着调用栈再次抛出。
throw
关键字,可是没必要使用new
关键字来建立异常实例。throw
结构是一个表达式,能做为另外一个表达式的一部分使用。当使用带有catch
和finally
子句的try
结构来处理异常时,下面是一个典型的结构:
Java
最大区别就是throws
子句没有出如今代码中:若是使用Java
来写这个函数,你会显示地在函数声明上面写上throws IOException
。这是由于IOException
是一个受检异常,在Java
中,这种异常必须显示地处理,必须声明你的函数能抛出全部的受检异常。
kotlin
不区分受检异常和未受检异常,没必要指定函数抛出的异常,并且能够处理也能够不处理异常。BufferReader.close
可能抛出须要处理的受检异常,若是关闭失败,大多数程序不会采起什么有意义的行动,因此捕获来自close
方法的异常所需的代码是多余的。kotlin
中的try
关键字就像if
和when
同样,引入了一个表达式,能够把它的值赋给一个变量,而且须要用花括号把语句主体括起来。若是主体包含多个表达式,那么整个try
表达式的值就是最后一个表达式的值。