在19年的Google I/O大会上,Kotlin 成为 Android 开发首选语言。而著名的OkHttp 已经开始用 Kotlin 进行重写工做。是时候经过写博客概括来巩固Kotlin基础知识。java
Kotlin中使用val关键字声明常量(即变量初始化以后不可再次赋值),var关键字声明变量。android
变量定义时能够不显示指定类型,编译器会根据其初始化器的类型进行推断。数组
//自动推断出 `Int` 类型
var daqi = 1
//能够显式地指定变量的类型
val a :String = "daqi"
//若是变量没有初始化器,须要显式地指定它的类型
val c: Int
c = 3
复制代码
当编译器能确保val变量只有惟一一条初始化语句会被执行,能够根据条件对它初始化不一样的值。安全
val daqi:String
var isChange = true
if (isChange){
daqi = "1"
}else{
daqi = "2"
}
复制代码
val变量的引用自身是不可变的,可是它指向的对象是可变的。bash
val languages = arrayListOf("Java")
languages.add("Kotlin")
复制代码
var 关键字容许变量改变本身的值,但不能改变本身的类型。ide
var daqi = 1
//编译不经过
daqi = ""
复制代码
(三)、定义函数 Kotlin 中使用 fun 关键字声明函数。 完整的函数定义:函数
修饰符(默认public)+ fun + 方法名 + (参数列表) :返回值 {
函数体
}
复制代码
public fun daqi(name:String):String {
}
复制代码
当单个表达式构成完整的函数体时,能够直接去掉 {} 和 return 语句,函数的返回值类型编译器也会自动推断。这种函数就是表达式函数。工具
fun sum(a: Int, b: Int) = a + b
复制代码
语句和表达式的区别在于:post
在 Java 中,全部的控制结构都是语句。而在 Kotlin 中,除了循环( for, do 和 do/while )之外大多数控制结构都是表达式(例如:if、 when 以及 try 属于表达式)ui
表达式函数不光用在些简单的单行函数中 ,也能够用在对更复杂的单个表达式求值的函数中。
fun max(a: Int, b: Int ) = if (a > b) a else b
复制代码
相似Java的返回值类型为void的函数
fun daqi():Unit{
}
复制代码
可省略Unit类型
fun daqi(){
}
复制代码
在 Java 中,当须要打印变量描述和其值时,每每以下打印:
String str = "daqi";
System.out.println("str = " + str);
复制代码
Kotlin支持字符串模板,能够在字符串中引用局部变量,但须要在变量名前加上$。表达式会进行静态检查, 若是$引用一个不存在的变量,代码不会编译经过。
val str = "daqi"
printlin("str = $str")
复制代码
$不只限于引用于简单的变量名称,还能够引用更复杂的表达式。
val daqi = intArrayOf(1,2,3)
println("${daqi[0]}")
复制代码
在$引用的表达式内(即花括号{}中)能够直接嵌套双引号
println("daqi的第一个元素: ${if(daqi.size > 0) daqi[0] else "null"}")
复制代码
当须要打印$符号时,能够对其进行转义,或者利用表达式对其进行打印:
//打印结果为:$str
val str = "daqi"
println("\$str")
println(${'$'}daqi)
复制代码
在java中定义一个简单类:
public class Person{
private final String name;
public Person(String name){
this.name = name;
}
public String getName(){
return name;
}
}
复制代码
用Kotlin写的Person类(默认public修饰)
class Person(val name:String)
复制代码
延伸:若想知道Kotlin对应的具体Java实现,能够经过idea的工具,对Kotlin文件进行反编译:
Tools ->Kotlin -> Show Kotlin Bytecode -> 右侧弹出字节码框 ->左上角 Decompile按钮
在Kotlin中,当你声明属性的时候,也就声明了对应的访问器(即get和set)
val属性只有一个getter,var属性既有 getter 和 setter。 声明一个属性的完整语法:
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
复制代码
其中,初始化器,getter 和 setter 都是可选的。若是类型能够从初始化器或者getter 返回值中推断出来,也能够省略。 访问器的默认实现很是简单,即对对应变量的返回和更改。
当须要在值被访问或修改时提供额外的逻辑,能够经过自定义getter和setter
在Kotlin中的实现
class Rectangle(val height:Int,val width:Int){
val isSquare:Boolean
get(){
return height == width
}
}
复制代码
对应的Java实现:
在Kotlin中实现:
class Rectangle(val height:Int,val width:Int){
var isSquare:Boolean = false
set(value) {
field = value
}
}
复制代码
在setter方法中,使用特殊的标识符field来访问支持字段(幕后字段)的值。具体幕后字段后面再说。
Kolin中,名称以is开头的变量。转换成对应的Java get 和 set 方法时,getter不会添加任何的前准,setter名称中的is会被替换成set。
class Person(
var isDaqi:Boolean = false
)
复制代码
该对象在Java中的访问器为:
Kotlin中 while 和 do-while循环,其语法与Java的基本没区别。
而for循环仅以一种形式存在,和for-each差很少。但用 in 取代了 :
fun iterationArray(args:Array<String>){
for (str in args) {
}
}
复制代码
for循环还能够遍历区间。区间本质上是两个值之间的间隔。使用..运算符表示区间。
Kotlin中的区间是闭合区间,即结束值也是区间的一部分。而区间默认迭代步长为1。
val oneToTen = 1..10
复制代码
能够经过step关键字修改步长。遍历时,i变量其增加幅度将变为2,即每次迭代时都会自增2。
for(i in 0..100 step 2){
}
复制代码
若是想要一个半闭合区间,即结束值不属于区间的一部分,可使用until关键字,
val oneToNine = 1 until 10
复制代码
若是须要一个倒序的区间,可使用downTo关键字
val tenToOne = 10 downTo 1
复制代码
此时,将从10一直递减到1进行循环。downTo表示的区间也是一个闭合区间。
若是想实现普通for循环同样,对数据索引进行循环,可使用数组的indices变量
for (i in args.indices) {
println(args[i])
}
复制代码
在Kotlin中,if是一个表达式,即它会返回一个值。
if的分支为代码块时,最后的表达式将做为该代码块的值:
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
复制代码
Kotlin中的when,对应的是Java中的switch,但比起更增强大。
when 将它的参数与全部的分支条件按顺序比较,直到某个分支知足条件,执行其分支对应的代码。当多分支须要用相同的方式处理时,能够把其放在一块儿,用逗号分隔。
当when做为表达式使用时,必须有 else 分支, 除非编译器检测出全部的可能状况都已经被覆盖。(例如枚举类)
when (x) {
0, 1 -> print("x == 0 or x == 1")
2 -> print("x == 2")
else -> print("otherwise")
}
复制代码
有没有发现,没有了那繁琐的case和break!!
when的参数无关紧要,而且无限制类型!并且能够用任意表达式做为分支条件。(switch要求必须使用常量做为分支条件~)
when做为表达式函数的的函数体,直接使用函数的参数,自身并没有设置参数。并在条件语句中使用in或者!in 判断一个变量是否在区间或者集合中。
fun daqi(num:Int,intArray: IntArray) = when{
num in 1..10 -> "1~10"
num !in intArray -> "no in Array"
else -> "other"
}
复制代码
when 也能够用来取代 if-else if链.
fun daqi(num:Int) = when{
num < 0 -> "小于0"
num >0 && num < 10 -> "1..10"
else -> "other"
}
复制代码
is能够检查一个变量是不是某种类型,再配合智能转换(检查过某个变量的类型后,再也不须要再转换它,直接能够把它看成检查过的类型使用)能够很方便的对进行类型安全操做。
//Any相似于Java的Object
fun daqi(num:Any) = when(num){
is String -> {
//此时num已经为String类型
println("该变量类型为String,获取其长度")
println(num.length)
}
is Int -> {
//此时num已经为Int类型
println("该变量类型为Int,将其与10进行对比")
num.rangeTo(10)
}
else -> "other"
}
复制代码
Kotlin的异常处理与Java相似。当抛出异常时,不须要使用new关键字建立异常实例。
var daqi:String? = null
if (daqi == null){
throw NullPointerException("daqi is null")
}
复制代码
try也能够做为表达式,将其赋值给变量。当代码执行正常,则try代码块中最后一个表达式做为结果,若是捕获到异常,对应catch代码块中最后一个表达式做为结果。finally 块中的内容不会影响表达式的结果。
fun readNumber(reader:BufferedReader):Int? = try{
Integer.parseInt(reader.readLine())
}catch(e:NumberFormatException){
null
}catch (e:NullPointerException){
null
}finally {
reader.close()
}
复制代码
能够有0到多个 catch 块。finally 块能够省略。 可是 catch 与 finally 块至少应该存在一个。
kotlin中用两个关键字enum和class声明枚举类。enum是一个软关键字,只有当它出如今class前面时才有特殊的意义。
声明普通枚举类:
enum class Color{
RED,BLUE
}
复制代码
声明带属性的枚举类:
enum class Color(val r:Int,val g:Int,val b:Int){
RED(255,0,0),BLUE(0,0,255);
fun rgb = (r * 256 + g) * 256 + b
}
复制代码
若是在枚举类型中定义任何方法,须要使用分号;把枚举常量列表和方法定义分开。