初识Kotlin

这是一个新文集,专门用于记录学习 Kotlin 时遇到的一些问题或者心得体会。由于个人水平有限,文章难免会有错误之处,望大佬不吝指教。

Kotlin 由来已久,在17年被谷歌纳为了 Android 开发的一级语言,相必大家也多少有些许了解。在开发工作中,还没能正式的将项目来使用 Kotlin 开发,但是了解 Kotlin 显然已是迫在眉睫了。

旧项目引入 Kotlin 开发

如果你原来的项目使用 Java 编写的,可以完全放心,我们可以从现在开始每一个新文件都使用 Kotlin 来编写,Kotlin 与 Java 是百分百的可互相操作的。我们完全可以在保持原项目结构不便的情况下,来使用 Kotlin 进行后续的开发。

1 引入 Kotlin

  1. 在项目级 build.gradle 文件中引入
buildscript {
    ext.kotlin_version = '1.2.41'
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
  1. 在模块级 build.gradle 文件中引入
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
  1. 同步项目,开始使用 Kotlin 开始开发

此时你新建一个 Activity 的话,AS 将提示你可以选择使用 Kotlin 来进行开发;
新建Activity

2 开始开发

打开我们刚刚新建的这个 Activity,我们来看看 Kotlin 新建的页面与 Java 文件有那些区别;

class TestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
    }
}

在 Kotlin 中申明类也是使用关键字 “class”,类之间的继承使用 “:” ,注意如果被继承的父类也是一个 Kotlin 类文件(.kt),那么这个父类必须要使用 open 关键字修饰。在 Kotlin 中类默认状况相当于在 Java 中使用 final 修饰。

另外 Kotlin 支持 override 父类的成员变量,在父类中使用 open 关键字修饰的成员变量,在子类中可以使用 override 来重写,这一点在 Java 中是不支持的。

由于我们在前面引入了 apply plugin: 'kotlin-android-extensions' ,这使得我们可以直接在 Activity 中使用控件的 id 来调用控件,而无需在采用声明 - findViewById这种方式来实例化空间了。

例如我们在 xml 文件中放一个 TextView 控件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/mTvText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="这是一个测试的文字"
        android:textColor="#ff00ff"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

我们可以这样在 Activity 中操作:

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        var oldText = mTvText.text
        var newText = "这是一个新的字符串"
        mTvText.text=newText
    }

上述代码中,我们可以把 text 直接看成是 TextView 的一个公开的成员变量来使用,省去了 get/set 方法,这样的例子在 Kotlin 中还有很多。

在 Kotlin 中,我们使用 var 来声明一个可以读写的变量,使用 val 来声明一个只读变量。使用 val 声明的变量,在初始化其值后不允许再次赋值。与 Java 不同的是,在 Kotlin 中申明一个变量不一定需要显示声明,Kotlin 可以自动的推断出一个变量的类型,一个变量在类型确定之后不可以修改其类型。

var a: String = ""  //显示声明 a 为 String 类型
var b=1                //自动推断出 b 为 int

空安全

Kotlin 是默认空安全的,除非在变量在声明时使用 “?” 来标注该变量可以为 null,否则所有变量默认都是不可为 null,这样可以最大程度的避免空指针异常。

手动声明该变量可以为null

通常我们在 Android 编程时,都会在类中事先声明大量的变量,这些变量并不是都能在声明时初始化,往往很多都是在 Activity 的声明周期里完成的初始化。

但是在 Kotlin 中 你会发现有这种情况:
属性必须初始化或者是抽象的

面对这种情况有两种解决方法:
1. 在 init 代码块中初始化
init代码块
2. 使用 lateinitlazy 进行延时初始化
lateinit 用于 var 变量,lazy 用于 val 只读变量。
lateinit 延时初始化

空判断

如果我们已经显式的声明了一个变量可以为 null,那么在对这个变量进行操作时,我们需要对改变了进行空判断,这一点 Java 中也是一样的。

这样写在 Java 中是可以通过的,但是 Kotlin 中不可以
Java 中允许这样书写代码

显而易见的,如果是 Java 代码,运行到此处的时候回报空指针异常,导致程序崩溃。

在Kotlin 中我们有多重方式来进行空判断:
1. 传统的 Java 式在条件中显示检查 null

fun print(){
        var nullString: String? = null
        if (nullString != null) {
            println(nullString.length)
        } else {
            println("empty")
        }
    }
  1. 使用安全调用 “?.” 操作符
    ?. 安全调用操作符
    使用该操作符时,如果对象为 null,则不会调用该对象的方法,并且返回 null,不为 null 则正常执行
    相当于:
if(nullString == null){
    return null
}else{
    return nullString.lenght
}
  1. Elvis 猫王操作符 “?:
    当我们有一个可空的引用 r 时,我们可以说“如果 r 非空,我使用它;否则使用某个非空的值 x”,如下(注意:这是 kotlin 特有的操作,相当于 Java 中的三元操作符,但是 Kotlin 更为强大允许将 if - else 语句块中最后一句当成返回值返回):
val l: Int = if (b != null) b.length else -1

我们可以将它简化为:

val l = b?.length ?: -1

Elvis 操作符
可以看出,变量 b 直到运算的一刻才转型成字符型,这一操作在 Java 中是不可以的。需要注意的是,如果一个对象被声明为可能为空,那么除非是采取方法1在条件中判断 null,否则我们必须采用安全调用的方式。

4.使用 “!!” 运算符
上述的几种方式都是让我们如何避免空指针异常,但有时我们需要在代码里抛出这个异常,这一操作需求在 Java 里是不需要的,因为只要我们没有做空判断,代码执行到此处如果对象为空,必然会 NPE (NullPointerException)。但是在 Kotlin 里一个被声明为可空的变量是不能直接被调用的(见上文),这时我们就需要 “!!” 操作符,这个操作符可以使编译器忽略此处的空检查,当对象为空时,运行到此处会 NPE。
!! 操作符抛出 NPE

上述的四种方法就是我们在 Kotlin 中最常用的四种空判断方式,下面我们来总结一下:
- 当我们需要一个常规的空判断时,使用方法1;
- 当我们需要在对象为空时,表达式结果为空,使用方法2;
- 当我们需要在对象为空时,返回另一个表达式或者值,使用方法3;
- 当我们需要在对象为空时能正常的抛出 NPE,使用方法4;

最后给大家看一个在 Kotlin 中才能使用的骚操作
安全调用 、Elvis 操作符、if 表达式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章