Kotlin知识概括(一) —— 基础语法

前序

        在19年的Google I/O大会上,Kotlin 成为 Android 开发首选语言。而著名的OkHttp 已经开始用 Kotlin 进行重写工做。是时候经过写博客概括来巩固Kotlin基础知识。java

(一)、语法上的变动

  • 建立对象不须要new关键字
  • 语句不须要;结尾,加;也无所谓
  • 变量类型后置,即变量名在前,变量类型在后。例如 str:String
  • 使用 println() 替代 System.out.println()

(二)、定义变量

        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按钮

总体基本和Java类类似,可是该类被定义为final类,即太监类,不可被继承。

setter 和 getter

    在Kotlin中,当你声明属性的时候,也就声明了对应的访问器(即get和set)

    val属性只有一个getter,var属性既有 getter 和 setter。 声明一个属性的完整语法:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]
复制代码

    其中,初始化器,getter 和 setter 都是可选的。若是类型能够从初始化器或者getter 返回值中推断出来,也能够省略。 访问器的默认实现很是简单,即对对应变量的返回和更改。

当须要在值被访问或修改时提供额外的逻辑,能够经过自定义getter和setter

自定义getter

在Kotlin中的实现

class Rectangle(val height:Int,val width:Int){
    val isSquare:Boolean
        get(){
        	return height == width
    	}
}
复制代码

对应的Java实现:

自定义setter

在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])
}
复制代码

(六)、if表达式

在Kotlin中,if是一个表达式,即它会返回一个值。

if的分支为代码块时,最后的表达式将做为该代码块的值:

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}
复制代码

(七)、when表达式

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中的异常

    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
}
复制代码

若是在枚举类型中定义任何方法,须要使用分号;把枚举常量列表和方法定义分开。

参考资料:

android Kotlin系列:

Kotlin知识概括(一) —— 基础语法

Kotlin知识概括(二) —— 让函数更好调用

Kotlin知识概括(三) —— 顶层成员与扩展

Kotlin知识概括(四) —— 接口和类

Kotlin知识概括(五) —— Lambda

Kotlin知识概括(六) —— 类型系统

Kotlin知识概括(七) —— 集合

Kotlin知识概括(八) —— 序列

Kotlin知识概括(九) —— 约定

Kotlin知识概括(十) —— 委托

Kotlin知识概括(十一) —— 高阶函数

Kotlin知识概括(十二) —— 泛型

Kotlin知识概括(十三) —— 注解

Kotlin知识概括(十四) —— 反射

相关文章
相关标签/搜索