Kotlin入门

Kotlin简介

Kotlin是什么

Kotlin是JetBrains公司开发的一门语言,一圣彼得堡附近的Kotlin岛屿来命名的。Kotlin是运行在JVM上面的一门静态强类型语言,可以编译成JavaScript源码,运行在浏览器上,与Java100%兼容。

Kotlin的特性

为什么有了Java还需要有Kotlin?下面就看看Kotlin的一些特性吧:

  • 空类型安全
  • Lambda表达式
  • 扩展方法
  • 类型推导
  • 胜任Java能做的所有事情,使用起来比Java简单,例如没有句末分号

Kotlin相关参考资料

https://kotlinlang.org

https://blog.jetbrains.com/kotlin/

https://github.com/JetBrains/kotlin

Kotlin环境搭建

Kotlin练习环境搭建之--Hello Word!

下面我们先用IDEA来创建一个项目,打开IDEA,创建项目,选择Kotlin(JVM),如下图所示:

Kotlin创建项目.png
Tips:如果没有Kotlin选项,请先安装Kotlin插件,创建项目需要选择lib库。
Tips:首次创建项目需要Index一两分钟。

与Java一样,在src目录下面创建一个Package,创建.kt文件:

fun main(args: Array<out String>) {
    print("Hello Word\n")
    //创建类的时候不需要new关键字了
    print(MyBean(1, "test bean"))
}

//Kotlin风格的数据对象
data class MyBean(var id: Int, var name: String)

那么程序就会输出:

Hello Word
MyBean(id=1, name=test bean)

Kotlin练习环境搭建之--使用Gradle搭建环境

Gradle是一个依赖管理的工具,以前我们都是直接把jar包等源码直接拷贝进来的,但是这样很麻烦。有了Gradle之后,我们就可以通过脚本或者图形化界面进行依赖管理了,对以后依赖库的升级维护也很方便。

同样用IDEA进行开发,下面我们创建一个项目,选择Gradle、Kotlin,如下图所示:

Gradle创建Java与Kotlin项目.png

接下来配置构件信息,其中包括代表公司或者组织的GroupId,代表自己在公司或者组织里面的代表自己的ArticleFactId,然后就是构件的版本:

配置构件的信息.png

然后就是配置Gradle,这里笔者使用自己本地的Gradle,然后选择生成一些重要的文件夹,例如src/main/java目录:

配置Gradle.png

项目创建好之后如下:

项目一览.png

工具已经帮我们创建好需要的目录了。我们下面来看一些与Gradle相关的重要文件:

settings.gradle:是存放每个module的信息的,其内容如下:

rootProject.name = 'KotlinDemo'

build.gradle,与build相关的脚本,其内容如下:

group 'nan.com'
version '1.0-SNAPSHOT'

buildscript {
    repositories {
        //下面的dependencies中,插件的地址
        jcenter()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.4"
    }
}

//标识Java与Kotlin工程,存放着与编译相关的一系列指令集
apply plugin: 'java'
apply plugin: 'kotlin'

//标识Java的版本,这里没有使用到
sourceCompatibility = 1.5

repositories {
    //module中的依赖的地址
    jcenter()
}

//Gradle中最重要的功能--依赖管理
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.4"
    testCompile group: 'junit', name: 'junit', version: '4.11'
}

使用Gradle进行依赖管理

由于Kotlin中,反射包是独立与基础包的,因此我们以反射这个包为例子,介绍一下使用Gradle进行依赖管理。

修改build.gradle:

//Gradle中最重要的功能--依赖管理
dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib:1.0.4"
    //增加反射依赖
    compile "org.jetbrains.kotlin:kotlin-reflect:1.0.4"
    testCompile group: 'junit', name: 'junit', version: '4.11'
}

然后就可以在代码中进行反射操作了,例如我们拿到Person类的构造方法:

fun main(args: Array<String>) {
    Person::class.constructors.map {
        print(it)
    }

    //也可以通过代码提示直接改成这种写法
    Person::class.constructors.map(::print)
}

data class Person(var id: Int, var name: String) {

}

Kotlin空指针安全

我们先来看一个例子,我们先创建一个Person类:

data class Person(var id: Int, var name: String) {

}

然后在Java代码中new这个类:

public class Test {
public static void main(String[] args) {
//注意第二个参数传了null
Person p = new Person(1, null);
}
}

运行的时候发现报错:

Exception in thread "main" java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Person.<init>, parameter name
    at Person.<init>(Test.kt)
    at Test.main(Test.java:7)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

因为Kotlin的类中实质上加了@notnull注解。

同样地,我们在Kotlin中使用这个Person,也传个null进去:

fun main(args: Array<String>) {
    val p = Person(1, null)
}

你会发现,根本就编译不过。这就是Kotlin的类型安全的体现了,把一些空指针的问题提前到了编译阶段,而不是运行阶段,这一点真的很重要。

Tips:可以通过code -- Conver Java File to Kotlin File或者直接粘贴,把Java代码转换Kotlin代码。

如果你的Person类中的name可以传null的话,就需要加上"?"标识符,完整的示例如下:

fun main(args: Array<String>) {
    //不会报错了
    val p = Person(1, null)
}

data class Person(var id: Int, var name: String?) {
    
}

Kotlin中的集合

Kotlin中的集合

与Java中用[]代表集合不一样,在Kotlin中用Array<T>表示集合,例如:

fun main(args: Array<String>) {

}

与Java类似,可以在泛型中指定类型应该继承哪个类型,Java中用extends关键字,在Kotlin中用out关键字,例如:

fun main(args: Array<out Bean>) {

}

集合的基本遍历

下面是Kotlin中集合遍历的集中方法:

fun main(args: Array<String>) {

    for (arg in args) {
        print(arg)
    }

    args.map({ print(it) })

    args.map() {
        print(it)
    }

    args.map { print(it) }

    args.map(::print)
}
Tips:命令行参数可以在run--Edit Configuration中修改。
  • 第一种没有什么好说的,与Java类似。

  • 第二种开始,使用了map方法进行遍历,map方法是Kotlin中的Arrays类提供的遍历集合的函数,定义如下:

      //map方法是一个扩展方法,只有一个Lambda表达式参数,接收的是一个T类型的参数,返回R类型。T类型就是我们要迭代的String类型,而R类型没有明确指定
      public inline fun <T, R> Array<out T>.map(transform: (T) -> R): List<R> {
          return mapTo(ArrayList<R>(size), transform)
      }
    

因此呢,map方法可以传进去一个 {表达式} 作为参数。而print接收一个it参数,it是迭代的String,返回的是空类型(Kotlin中空类型是Unit),完全符合map中的Lambda表达式的要求。因此可以传进去。

  • 第三种,既然map只有一个Lambda表达式参数,那么可以把大括号后置,这是第三种。
  • 第四中,在第三种的基础上,既然大括号可以省略,那么前面的()也省略了。
  • 第五种,直接把函数的引用传进去(通过两个分号::)
Kotlin中的空用Unit类型表示,无返回值的函数可以这样写(一般无返回值直接省略而已):
fun main(args: Array<String>) :Unit{

}

使用flatMap扁平化集合

现在有一个需求:

将apple_bus_cat dog_egg_fly good_hook_it
扁平化输出为:apple:5 bus:3 cat:3 dog:3 egg:3 fly:3 good:4 hook:4 it:2 

在Java中是这样做的:

public static void main(String[] args) {
    for (String arg : args) {
        String[] split = arg.split("_");
        for (String s : split) {
            System.out.print(s + ":" + s.length() + " ");
        }
    }
}

在Kotlin中是通过flatMap进行扁平化,然后再通过map进行遍历输出的:

fun main(vararg args: String) {

    args.flatMap {
        it.split("_")
    }.map {
        print("$it:${it.length} ")
    }

}

程序中我们用到了flatMap对集合进行了一次扁平化,返回了一个数组,最终丢给map。下面我们来看看flatMap的源码:

//实际上flatMap也是传入一个Lambda表达式,将T类型(String)的数据转换成可迭代的R类型数据,因此String的split符合要求
public inline fun <T, R> Array<out T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
    return flatMapTo(ArrayList<R>(), transform)
}

//flatMap最终会调用flatMapTo方法,对集合进行扁平化,把每一个转换出来的数据都放到一个列表里面,因此,虽然我们有apple_bus_cat dog_egg_fly good_hook_it三组数据,但是最终被切割成apple bus cat dog egg fly good hook it这样的一个数组,然后再通过map进行遍历输出即可
public inline fun <T, R, C : MutableCollection<in R>> Array<out T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
    for (element in this) {
        val list = transform(element)
        destination.addAll(list)
    }
    return destination
}
Tips:Kotlin中的可变长参数是用vararg关键字来声明的。
Tips:与JS类似,双引号""字符串的拼接中可以使用$符号。
Tips:由于这里迭代中需要传参,因此不可以省略成args.map(::print)这种形式了(这种形式默认是把it传进print方法中了)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,737评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,103评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,710评论 0 326
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,909评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,794评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,557评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,939评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,572评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,852评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,871评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,692评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,490评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,939评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,114评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,409评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,971评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,176评论 2 339

推荐阅读更多精彩内容

  • Kotlin的优势 代码简洁高效、强大的when语法,不用写分号结尾,findViewById光荣退休,空指针安全...
    Windy_816阅读 1,276评论 1 6
  • kotlin是 JetBrains 在 2010 年推出的基于 JVM 的新编程语言。开发者称,设计它的目的是避免...
    allen_li阅读 2,942评论 0 3
  • why kotlin kotlin引入现代语言的所有特性,而没有引入新的限制,它适合android原生开发 兼容性...
    熹哥阅读 695评论 2 6
  • 此文章主要写了我在学习kotlin的历程中的一些感悟和体会。供入门的同学参考。 一、Kotlin优点 1.扩展函数...
    cy_why阅读 981评论 0 3
  • 因为食堂太难吃呢。经常十来块打一份两荤一素,吃一半到一半。即吃不好又吃不饱。那就撸起袖子,自己干。从买第一个厨具到...
    yydtk2019阅读 87评论 0 1