Kotlin基础语法教程(一)
Kotlin概述
Kotlin是由开发过IntelliJ IDEA、Android Studio、PyCharm等IDE的著名IDE厂商JetBrains公司设计并开源的编程语言。2011年7月推出的Kotlin项目深受《Effective Java》的影响,直到2016年2月15日第一个官方稳定版本Kotlin v1.0才正式发布,2017年Google I/O开发者大会中,Google宣布Kotlin成为Android开发的一级语言,Kotlin “转正”。
Kotlin是一种运行在JVM上的静态类型编程语言,可以编译为Java字节码,同时也可以编译成JavaScript、本地(Native)代码,方便在没有JVM的设备上运行。Kotlin语言具有以下特点:
与Java的编译、运行速度相似
比Java更安全、简洁
比最成熟的竞争者Scala更简洁
Kotlin在语法上具有很多下一代编程语言静态语言特性:如类型推断、函数式编程、多范式支持、可空性表达、扩展函数、模式匹配等。
Kotlin与Java具有良好的兼容性,与Java高度可互操作,在同一项目的开发中可以同时使用两种语言进行编写(仅限于不同文件中,不能在同一文件中使用两种语言),如Kotlin可以直接调用Java的代码,而Java调用Kotlin需要使用一些注解,但也不是很复杂。IntelliJ IDEA提供了Java代码到Kotlin代码的转换功能,您只需将Java代码拷贝粘贴到.kt文件中,IDE就会自动将其转换为Kotlin代码,方便Java学习者顺利过渡到Kotlin。
Kotlin支持像Python一样的REPL环境,可以很方便的进行代码测试,对于语言的学习十分有帮助,配置环境变量后只需要在命令行输入kotlinc,即可开启REPL环境。
Kotlin REPL
这篇文章面向有Java语言基础的对Kotlin有兴趣的读者,内容比较基础,主要通过两种语言的对比进行说明。
基础语法
Hello World
创建项目
如图所示,使用IntelliJ IDEA新建项目时可选择Java,同时在右侧勾选Kotlin/JVM,或者直接新建Kotlin项目。
上述Kotlin代码的作用就是输出,看起来比Java等语言简单得多,Kotlin中通过关键字声明一个函数,是函数名,在这里是应用程序的入口;是参数,这里代表命令行参数,它的类型是字符串数组,需要注意的是Kotlin的变量名通常写在类型的前面,中间用冒号分开。
是Kotlin中的顶层函数,对应Java中的函数,顶层函数不属于任何类,可以直接拿来用,类似用法的顶层函数还有等。
Kotlin的语句最后的分号不是必须的,只有当多个语句写在同一行时,才必须用分号加以区分。
变量和数据类型常量和变量
Kotlin中声明变量通常使用,如上述代码中的变量,Kotlin语言支持变量类型的自动推断,通常都不需要显式的声明变量类型。
Kotlin变量分为(可变变量)和(只读变量,也称不可变变量、运行期常量),其中是可写的,在它的生命周期中可以被多次赋值,如上述代码中的和;而是只读的,它是在运行时初始化的,但仅能赋值一次,如对重新赋值会发生编译错误,只读变量相当于Java中用修饰的变量(并不完全相同)。只读变量的值只能被修改一次,并且不能被覆盖,这可以避免变量的值被错误的修改。
Kotlin的常量(编译期常量)用声明,仅能用于顶层常量和对象中的常量声明,如上述代码中的和对象中的常量,在函数中声明的则会发生编译错误,编译期常量相当于Java中用修饰的常量(并不完全相同),Kotlin中的常量只能是String类型或基本数据类型。
基本数据类型
下表展示了Kotlin中的8种基本数据类型对应的Java基本数据类型和Java包装类:
与Java不同,Kotlin的字符类型()不属于数值类型,Kotlin中的基本数据类型没有对应的包装类,编译器会视具体情况将其编译为Java基本数据类型或者包装类对象。
上述代码演示了Kotlin中数值类型的字面量,其中比较特殊的是:
Kotlin的小数默认是类型,不能加或后缀
为了避免小写字母和数字的混淆,Kotlin不允许使用小写字母作为Long类型整数的后缀,必须使用大写字母
使用进行比较长的数字的分割时,不强制要求每3位数字分割一次
非空类型与可空类型
为了避免Java中经常出现的空指针异常(),Kotlin的类型默认定义为非空,即不可接收空值(),直接对非空类型变量赋值会发生编译错误。当我们确认需要可空类型时,可以通过在非空类型后面加一问号(),此时的变量可以接收空值,如:
非空类型永远不可能为null,而可空类型则存在潜在的空指针风险,Kotlin不允许可空类型对象直接调用非空类型对象的属性或函数,也不能把可空类型数据赋值给非空类型变量或是传递给非空类型参数。为了使可空类型能够调用非空类型的方法,Kotlin提供了以下几个运算符:
非空断言运算符:
安全调用运算符:
安全转换运算符:
Elvis运算符(空值合并运算符):
下面对这几个运算符进行介绍:
非空断言运算符:非空断言运算符用于断言一个可空类型变量不为空值,使用这个运算符会存在抛出空指针异常()的风险。
上述代码由于对值为空的变量进行了非空断言,运行时会抛出空指针异常。在最新版的Kotlin中,若已经检查了变量非空,则允许不使用非空断言运算符直接调用非空类型的属性和函数。
安全调用运算符:该运算符用于对可空类型变量安全的调用非空类型的属性或函数,而不会抛出空指针异常,当对象为空时,直接返回空值(),否则进行调用并返回结果。
它等价于以下代码:
安全转换运算符:在Kotlin中使用和进行强制类型转换,这部分内容将在面向对象的多态部分进行说明。
Elvis运算符:该运算符名称的由来是像“猫王”(美国摇滚歌手)埃尔维斯·普雷斯利(Elvis Presley)的头型和眼睛,其作用是空值合并。该运算符是一个二元运算符(注意Kotlin不存在这个三元运算符),语法是,作用是当数据非空时,直接返回数据,而当数据为空时,返回合并到的数据。利用该运算符,可以很容易的把可空类型转换为非空类型。
等价于如下代码:
函数声明
Kotlin既有独立于类的顶层函数,也有类方法,为了避免混淆,这里统称为函数。上述中演示了参数的定义,下面的代码中演示了返回值,返回值应在函数的参数列表括号之后显式地声明。
Kotlin的函数(包括顶层函数和类函数)可以带有参数默认值,而Java中想要实现类似的功能则需要冗长的方法重载或使用builder模式。
上述代码中对参数使用了默认值,在调用函数不提供参数时其值为,调用时使用了命名参数,采用命名参数可以增加代码的可读性,参数顺序可以与函数定义时不一致,建议带有默认值的参数放在参数列表的最后面,需要注意的是在调用函数时一旦其中一个参数采用了命名参数,其后所有的参数都必须采用命名参数形式传递。上述代码中函数的返回值类型定义为,相当于Java中的类型,此处可以省略返回值类型。
字符串模板
原始字符串:使用三个双引号包起来的字符串,原始字符串中的将不被识别为转义,字符串中可以包含换行,如:
下面的代码是使用原始字符串输出三行内容,第2、3行都在行首开始,这样的代码有时看起来对齐的并不自然。
可以使用、裁剪函数来去除前导空格。
String类型的函数(方法)用于切割每一行开头相同数量的空格。
函数用于从字符串中每行的开头裁剪裁剪指定的字符串参数以及前面的全部空格,如果不提供参数,则以作为参数默认值。
Kotlin还支持类似于PHP中的字符串模板,利用这一特性,前面提供的函数可以进行如下改写:
在原始字符串和一般的字符串中都允许使用字符串模板,字符串模板能够简化字符串拼接的操作,字符串模板是以开头,其语法为或,如果想要在字符串中使用符号,请用或代替。
流程控制if语句/表达式
Kotlin简化了Java中的一些语句,将其变为具有返回值的表达式,主要有表达式、表达式、表达式、表达式函数体,示例代码如下:
when语句/表达式
Kotlin放弃了C和Java中的语句,采用一个新的语句/表达式,相比语句,语句/表达式要更加的强大、灵活。
是一个多分支的结构,像一样,的每一个分支都可以是一个代码块,表达式也具有返回值,它的值是块中最后的表达式的值。可以用任意表达式(不只是常量)作为分支条件,也可以把多个分支条件通过逗号放在一起,还可以用和加上一个区间检测一个值是否在一个区间或者集合中、用和加上一个类名判断是否是某个类的实例(Java中对应的是),如果所有分支都不满足,则会执行分支(可以没有)。
上述代码中的是区间运算符,如是生成闭区间[0, 59]内的整数数列,每个区间是一个可迭代的对象,Kotlin还提供了一个半开区间运算符,如则是生成半开区间[0,10)内的整数,Kotlin核心库中共提供了3个闭区间类:、和。
循环语句
Kotlin具有和C、Java类似的循环和循环,这里不再赘述,主要介绍循环。下面演示一个打印乘法口诀表的代码:
Kotlin的循环相当于Java的循环,但循环中的变量无需用或声明,循环可用于对范围或者集合进行遍历。结合生成递减数列的中缀运算符,可以实现更复杂的功能。
上述代码中的是生成一个递减数列,而则是设置数列的步长。
带标签的break和continue
与Java类似,Kotlin也支持带标签的break和continue语句,语法是在、或前面加上,使用标签时用,如:
Kotlin运算符算术运算符、逻辑运算符和关系运算符
Kotlin的算术运算符、逻辑运算符与Java一致,关系运算符与Java稍有不同,其中运算符对两个对象进行比较,调用的是对象的函数,则是对运算符的取反;而对引用类型的比较则需使用和运算符,用于判断两个引用是否指向同一个对象。当一个对象与进行显式的比较时,使用两种运算符效果相同,Kotlin会自动将转换为。
位运算符
Java和Kotlin的位运算符和Kotlin位运算符的示例如下表所示:
其他运算符
前面的介绍中提到了非空断言运算符、安全调用运算符、安全转换运算符、Elvis运算符等,Kotlin的y一些运算符是通过调用转换方法来实现的,下表介绍了一些运算符及其转换方法:
一元运算符
二元运算符
局部函数和匿名函数
Kotlin的函数可以声明在类内部,称为成员函数,还可以声明在另一函数的内部,称为局部函数。当函数只被调用一次时,可以声明为匿名函数。
上述代码中使用了表达式、参数默认值和命名参数、函数类型变量、匿名局部函数、表达式函数体、Lambda表达式和类型推断。
Kotlin支持函数类型,可以定义函数类型的变量,类似C语言中的函数指针,允许把函数作为参数传递,这是Kotlin对Java反射机制的增强实现,反射机制内容较多,这里只对函数类型进行说明:函数类型的格式为:,例如:表示空参数列表无返回值的函数类型,表示两个浮点型参数,返回值为浮点型的函数类型。
上述代码五个分支全部使用了匿名局部函数,其中分支是省略了函数名(匿名)的局部函数,分支进一步将使用表达式函数体简化了函数体并省略参数和返回值类型的声明(Kotlin会根据定义的接收函数的变量的类型进行推断),、和分支使用了Lambda表达式。
Lambda表达式是一种特殊的匿名函数,它是一个函数对象,其声明方式为{ 参数列表 -> 语句块 },Lambda表达式内部的返回值是语句块的最后一行,Lambda表达式的参数列表类型也支持自动推断,当某个参数在语句块中没有用到的时候,可以通过下划线占位,如分支,当Lambda只有一个参数时,可以省略参数,只写语句块,其中唯一的参数(隐式参数)用标识符代替。
Kotlin约定,在调用函数时,如果使用Lambda表达式作为参数,若Lambda表达式是最后一个参数,可以将Lambda表达式块移到参数列表括号的后面,而当只有这一个参数时,前面的小括号可以省略,如:
数组基本数据类型数组
Kotlin基本数据类型数组和Java基本数据类型数组的对应关系如下表所示:
Kotlin的数组都是通过使用顶层函数创建的,基本数据类型数组有3种创建方式,以类型为例,它们的函数声明如下:
:这里的表示这是一个可变参数,可变参数必须位于参数列表的最后一个,调用时需要提供零个或多个类型的数据
:该函数通过指定数组的元素个数创建数据类型默认值的数组,的默认值是0
:该函数第一个参数指定数组大小,第二个参数提供一个类型的函数,通常使用Lambda表达式,函数的第一个参数是数组的下标(从0开始)
对象数组
Kotlin中的对象数组对应Java中的包装类数组,其对应关系为:
对象数组也有3种创建方式,以类型为例:
:创建类型为的数组变量,提供一组相同数据类型的数据列表
:参数用于指定创建数组的大小,该函数用于创建一个类型为T的数组,所有的元素均为空值
:该函数第一个参数指定数组大小,第二个参数提供一个类型的函数,通常使用Lambda表达式,函数的第一个参数是数组的下标(从0开始)
领取专属 10元无门槛券
私享最新 技术干货