[1] —— 在项目中集成并使用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,这样可以最大程度的避免空指针异常。

var nullString: String? = null

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

但是在 Kotlin 中 你会发现有这种情况:


属性必须初始化或者是抽象的

面对这种情况有两种解决方法:

  1. init 代码块中初始化
var d:String
init {
    d = "init"
}
  1. 使用 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 表达式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容