├── .gitignore ├── 1.Kotlin简介 ├── images │ ├── Kotlin Logo.png │ ├── kotlin1.gif │ ├── kotlin10.png │ ├── kotlin11.png │ ├── kotlin12.png │ ├── kotlin13.png │ ├── kotlin14.png │ ├── kotlin15.png │ ├── kotlin16.png │ ├── kotlin17.png │ ├── kotlin2.png │ ├── kotlin3.png │ ├── kotlin4.png │ ├── kotlin5.png │ ├── kotlin6.png │ ├── kotlin7.png │ ├── kotlin8.png │ └── kotlin9.png └── 第1章 Kotlin简介.md ├── 10.Kotlin与Java互操作 ├── images │ ├── Kotlin与Java互操作1.png │ └── Kotlin与Java互操作2.png └── 第10章 Kotlin与Java互操作.md ├── 11.使用Kotlin集成SpringBoot开发Web服务端 ├── images │ ├── kotlin_springboot_01.png │ ├── kotlin_springboot_02.png │ ├── kotlin_springboot_03.png │ ├── kotlin_springboot_04.png │ ├── kotlin_springboot_05.png │ ├── kotlin_springboot_06.png │ ├── kotlin_springboot_07.png │ ├── kotlin_springboot_08.png │ ├── kotlin_springboot_09.png │ ├── kotlin_springboot_10.png │ ├── kotlin_springboot_11.png │ ├── kotlin_springboot_12.png │ └── kotlin_springboot_13.png └── 第11章 使用Kotlin集成SpringBoot开发Web服务端.md ├── 12.使用Kotlin集成Gradle开发 └── 第12章 使用Kotlin集成Gradle开发.md ├── 13.使用Kotlin和Anko的Android开发 ├── images │ ├── Anko1.png │ ├── Anko10.png │ ├── Anko11.png │ ├── Anko12.png │ ├── Anko13.png │ ├── Anko14.png │ ├── Anko15.png │ ├── Anko16.png │ ├── Anko17.png │ ├── Anko18.png │ ├── Anko19.png │ ├── Anko2.png │ ├── Anko3.png │ ├── Anko4.png │ ├── Anko5.png │ ├── Anko6.png │ ├── Anko7.png │ ├── Anko8.png │ └── Anko9.png └── 第13章 使用 Kotlin 和 Anko 的Android 开发.md ├── 14.使用 Kotlin DSL ├── images │ ├── dsl1.png │ └── dsl2.png └── 第14章 使用 Kotlin DSL.md ├── 15.Kotlin 文件IO操作与多线程 └── 第15章 Kotlin 文件IO操作与多线程.md ├── 16.使用 Kotlin Native ├── images │ ├── kotlin_native_01.png │ ├── kotlin_native_02.png │ ├── kotlin_native_03.png │ ├── kotlin_native_04.png │ ├── kotlin_native_05.png │ ├── kotlin_native_06.png │ ├── kotlin_native_07.png │ └── kotlin_native_08.png └── 第16章 使用 Kotlin Native.md ├── 2.快速开始:HelloWorld ├── images │ ├── kotlin_快速开始_01.png │ ├── kotlin_快速开始_02.png │ ├── kotlin_快速开始_03.png │ ├── kotlin_快速开始_04.png │ ├── kotlin_快速开始_05.png │ ├── kotlin_快速开始_06.png │ ├── kotlin_快速开始_07.png │ ├── kotlin_快速开始_08.png │ ├── kotlin_快速开始_09.png │ ├── kotlin_快速开始_10.png │ ├── kotlin_快速开始_11.png │ ├── kotlin_快速开始_12.png │ ├── kotlin_快速开始_13.png │ ├── kotlin_快速开始_14.png │ ├── kotlin_快速开始_15.png │ ├── kotlin_快速开始_16.png │ └── kotlin_快速开始_17.png ├── 第2章 快速开始:HelloWorld.md └── 第2章 快速开始:SpringbootRestful.md ├── 3.Kotlin语言基础 ├── images │ ├── kotlin_basics_01.png │ ├── kotlin_basics_02.png │ ├── kotlin_basics_03.png │ └── kotlin_basics_04.png └── 第3章 Kotlin语言基础.md ├── 4.基本数据类型与类型系统 ├── images │ ├── type_system_01.png │ ├── type_system_02.png │ ├── type_system_03.png │ ├── type_system_04.png │ ├── type_system_05.png │ ├── type_system_06.png │ ├── type_system_07.png │ ├── type_system_08.png │ └── type_system_09.png └── 第4章 基本数据类型与类型系统.md ├── 5.集合类 ├── images │ ├── collection.png │ ├── map.png │ └── set.png └── 第5章 集合类.md ├── 6.泛型 ├── images │ ├── 泛型1.png │ ├── 泛型2.png │ ├── 泛型3.png │ ├── 泛型4.png │ ├── 泛型5.png │ ├── 泛型6.png │ └── 泛型7.png └── 第6章 泛型.md ├── 7.面向对象编程 ├── images │ ├── oop1.png │ ├── oop2.png │ ├── oop3.png │ ├── oop4.png │ ├── oop5.png │ ├── oop6.png │ ├── oop7.png │ └── oop8.png └── 第7章 面向对象编程.md ├── 8.函数式编程 ├── images │ ├── 函数式编程1.png │ ├── 函数式编程10.png │ ├── 函数式编程11.png │ ├── 函数式编程2.png │ ├── 函数式编程3.png │ ├── 函数式编程4.png │ ├── 函数式编程5.png │ ├── 函数式编程6.png │ ├── 函数式编程7.png │ ├── 函数式编程8.png │ └── 函数式编程9.png └── 第8章 函数式编程.md ├── 9.协程 ├── images │ ├── coroutine1.png │ └── coroutine2.png └── 第9章 轻量级线程:协程.md ├── README.md ├── SUMMARY.md ├── assets ├── Kotlin for android developers.png ├── Kotlin 语言中文站.png ├── kotlin.jpg └── note.jpg ├── book.json ├── sword_preface.md ├── vedio ├── Kotlin 从入门到放弃.md ├── Kotlin 从零基础到进阶.md ├── Kotlin 系统入门到进阶.md ├── README.md └── images │ ├── kotlin学习视频1.png │ ├── kotlin学习视频2.png │ ├── kotlin学习视频3.png │ └── kotlin学习视频4.png └── 简介.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf -------------------------------------------------------------------------------- /1.Kotlin简介/images/Kotlin Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/Kotlin Logo.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin1.gif -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin10.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin11.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin12.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin13.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin14.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin15.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin16.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin17.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin2.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin3.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin4.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin5.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin6.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin7.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin8.png -------------------------------------------------------------------------------- /1.Kotlin简介/images/kotlin9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/1.Kotlin简介/images/kotlin9.png -------------------------------------------------------------------------------- /1.Kotlin简介/第1章 Kotlin简介.md: -------------------------------------------------------------------------------- 1 | 第1章 Kotlin简介 2 | === 3 | 4 | ## 1.1 kotlin简史 5 | 6 | ### 1.1.1 Kotlin概述 7 | 8 | >科特林岛(Котлин)是一座俄罗斯的岛屿,位于圣彼得堡以西约30公里处,形状狭长,东西长度约14公里,南北宽度约2公里,面积有16平方公里,扼守俄国进入芬兰湾的水道。科特林岛上建有喀琅施塔得市,为圣彼得堡下辖的城市。 9 | 10 | 11 | 我们这里讲的Kotlin,就是一门以这个Котлин岛命名的现代程序设计语言。它是一门静态类型编程语言,支持JVM平台,Android平台,浏览器JS运行环境,本地机器码等。支持与Java,Android 100% 完全互操作。 12 | 13 | ![Kotlin极简教程](images/Kotlin Logo.png) 14 | 15 | 其主要设计者是来自 Saint Petersburg, Russia JetBrains团队的布雷斯拉夫( [Andrey Breslav](https://twitter.com/abreslav) , https://www.linkedin.com/in/abreslav/ )等人,源码在github上,其实现主要是JetBrains团队成员以及开源贡献者。 16 | 17 | > 认识一个事物的最好的方式,首先是取了解它的历史。 18 | 19 | 我们先来简单看一下来自wikipedia[0]的Kotlin简历: 20 | 21 | | 标题 | 内容 | 22 | | --------- | ------------------------------------ | 23 | | 设计者 | JetBrains | 24 | | 实现者 | JetBrains与开源贡献者 | 25 | | 最新发行时间 | Kotlin 1.1.2(2017年4月25日,34天前) | 26 | | 最新测试版发行日期 | Kotlin 1.1.3 EAP(2017年5月27日,2天前 [1]) | 27 | | 类型系统 | 静态类型 | 28 | | 系统平台 | 输出Java虚拟机比特码以及JavaScript源代码 | 29 | | 操作系统 | 任何支持JVM或是JavaScript的解释器 | 30 | | 许可证 | Apache 2 | 31 | | 文件扩展名 | .kt | 32 | | 网站 | kotlinlang.org | 33 | | 启发语言 | Java、Scala、Groovy、C#、Gosu | 34 | 35 | (注:这里的日期时间,取的是本书当时写作时间) 36 | 37 | Kotlin的亲爹是大名鼎鼎的Jetbrains公司。它有一系列耳熟能详的产品,诸如Android程序员们天天用的Android Studio, Java程序员们天天用的IntelliJ IDEA, 还有前端的WebStorm, PhpStorm等等。所以说,使用IntelliJ IDEA了开发Kotlin程序将会非常便捷。 38 | 39 | Kotlin这个语言从一开始推出到如今,已经有六年了。官方正式发布首个稳定版本的时间相对比较晚(2016.2),这是一门比较新的语言。其大致发展简史如下: 40 | 41 | 42 | 2011年7月,JetBrains推出Kotlin项目。 43 | 44 | 2012年2月,JetBrains以Apache 2许可证开源此项目。 45 | 46 | 2016年2月15日,Kotlin v1.0(第一个官方稳定版本)发布。 47 | 48 | 2017 Google I/O 大会,Kotlin “转正”。 49 | 50 | 51 | Kotlin 具有很多现代(也有称下一代)静态编程语言的特性:如类型推断、多范式支持、可空性表达、扩展函数、模式匹配等。 52 | 53 | Kotlin的编译器kompiler可以被独立出来并嵌入到 Maven、Ant 或 Gradle 工具链中。这使得在 IDE 中开发的代码能够利用已有的机制来构建,可以在新环境中自由使用。 54 | 55 | Kotlin以K字打头的用语,甚至连 contributors 这类词也改成了kontributors。 56 | 57 | ### 1.1.2 Kotlin 元年:2016 58 | 59 | 2016 年是 Kotlin “元年(First year of Kotlin)”,官网给出了这样一幅图来展示它一年来的成绩: 60 | 61 | ![](images/kotlin1.gif) 62 | 63 | Github 上面的代码量破千万,8000多基于kotlin项目。使用 Kotlin 的人逐渐增多。 64 | 65 | Kotlin 是由工程师设计,各种细节设计非常切合工程师的需要。语法近似 Java 和 Scala,且已活跃在 Android 开发领域,被誉为 Android 平台的 Swift。 66 | 67 | 68 | 其主要设计目标: 69 | 70 | - 创建一种兼容 Java 的语言 71 | - 让它比 Java 更安全,能够静态检测常见的陷阱。如:引用空指针 72 | - 让它比 Java 更简洁,通过支持 variable type inference,higher-order functions (closures),extension functions,mixins and first-class delegation 等实现。 73 | - 让它比最成熟的竞争对手 Scala语言更加简单。 74 | 75 | Kotlin 的学习曲线极其平缓,学习量相当于一个框架。有经验的程序员阅读了文档即刻上手。 76 | 77 | ## 1.2 快速学习工具 78 | 79 | > 工欲善其事必先利其器 80 | 81 | ### 1.2.1 云端IDE 82 | 83 | 未来的是云的世界。不需要搭建本地开发运行环境,直接用浏览器打开 84 | 85 | > https://try.kotlinlang.org/ 86 | 87 | 你就可以直接使用云端IDE来即时编写Kotlin代码,并运行之。一个运行示例如下图: 88 | 89 | ![](images/kotlin2.png) 90 | 91 | ### 1.2.2 本地命令行环境搭建 92 | 93 | Kotlin是运行在JVM环境下的语言。首先我们要有JDK环境。 94 | 95 | 有时候我们并不需要打开IDE来做一些事情。打开 IDE 是件很麻烦的事情,在某些场景下,我们比较喜欢命令行。 96 | 97 | 使用命令行环境,我们可以方便地使用Kotlin REPL(Read-Eval-Print-Loop,交互式编程环境)。REPL可以实时编写Kotlin代码,并查看运行结果。通常REPL交互方式可以用于调试、测试以及试验某种想法。 98 | 99 | 下面我们讲下怎么搭建 Kotlin 命令行环境。 100 | 101 | Kotlin 命令行环境主要依赖就是Kotlin Compiler,目前最新版本是 1.1.2-2。其下载链接是: 102 | 103 | https://github.com/JetBrains/kotlin/releases/tag/v1.1.2-2 104 | 105 | 这个zip包里面就是Kotlin Compiler的核心依赖jar包。解压后,目录结构如下: 106 | 107 | ``` 108 | . 109 | ├── bin 110 | │   ├── kotlin 111 | │   ├── kotlin.bat 112 | │   ├── kotlinc 113 | │   ├── kotlinc-js 114 | │   ├── kotlinc-js.bat 115 | │   ├── kotlinc-jvm 116 | │   ├── kotlinc-jvm.bat 117 | │   └── kotlinc.bat 118 | ├── build.txt 119 | ├── lib 120 | │   ├── allopen-compiler-plugin.jar 121 | │   ├── android-extensions-compiler.jar 122 | │   ├── kotlin-annotation-processing.jar 123 | │   ├── kotlin-ant.jar 124 | │   ├── kotlin-build-common-test.jar 125 | │   ├── kotlin-compiler-client-embeddable.jar 126 | │   ├── kotlin-compiler.jar 127 | │   ├── kotlin-daemon-client.jar 128 | │   ├── kotlin-jslib-sources.jar 129 | │   ├── kotlin-jslib.jar 130 | │   ├── kotlin-preloader.jar 131 | │   ├── kotlin-reflect.jar 132 | │   ├── kotlin-runner.jar 133 | │   ├── kotlin-runtime-sources.jar 134 | │   ├── kotlin-runtime.jar 135 | │   ├── kotlin-script-runtime-sources.jar 136 | │   ├── kotlin-script-runtime.jar 137 | │   ├── kotlin-stdlib-js-sources.jar 138 | │   ├── kotlin-stdlib-js.jar 139 | │   ├── kotlin-stdlib-sources.jar 140 | │   ├── kotlin-stdlib.jar 141 | │   ├── kotlin-test-js.jar 142 | │   ├── kotlin-test.jar 143 | │   ├── noarg-compiler-plugin.jar 144 | │   ├── sam-with-receiver-compiler-plugin.jar 145 | │   └── source-sections-compiler-plugin.jar 146 | └── license 147 | ├── LICENSE.txt 148 | ├── NOTICE.txt 149 | └── third_party 150 | ├── args4j_LICENSE.txt 151 | ├── asm_license.txt 152 | ├── closure-compiler_LICENSE.txt 153 | ├── dart_LICENSE.txt 154 | ├── jshashtable_license.txt 155 | ├── json_LICENSE.txt 156 | ├── maven_LICENSE.txt 157 | ├── pcollections_LICENSE.txt 158 | ├── prototype_license.txt 159 | ├── rhino_LICENSE.txt 160 | ├── scala_license.txt 161 | ├── trove_license.txt 162 | └── trove_readme_license.txt 163 | 164 | 4 directories, 50 files 165 | ``` 166 | 167 | 其中,kotlinc,kotlin两个命令就是Kotlin语言的编译.kt文件和运行Kt.class文件命令。 168 | 169 | 我们来看一下kotlinc的命令: 170 | 171 | ```bash 172 | #!/usr/bin/env bash 173 | # 174 | ############################################################################## 175 | # Copyright 2002-2011, LAMP/EPFL 176 | # Copyright 2011-2015, JetBrains 177 | # 178 | # This is free software; see the distribution for copying conditions. 179 | # There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A 180 | # PARTICULAR PURPOSE. 181 | ############################################################################## 182 | 183 | cygwin=false; 184 | case "`uname`" in 185 | CYGWIN*) cygwin=true ;; 186 | esac 187 | 188 | # Based on findScalaHome() from scalac script 189 | findKotlinHome() { 190 | local source="${BASH_SOURCE[0]}" 191 | while [ -h "$source" ] ; do 192 | local linked="$(readlink "$source")" 193 | local dir="$(cd -P $(dirname "$source") && cd -P $(dirname "$linked") && pwd)" 194 | source="$dir/$(basename "$linked")" 195 | done 196 | (cd -P "$(dirname "$source")/.." && pwd) 197 | } 198 | 199 | KOTLIN_HOME="$(findKotlinHome)" 200 | 201 | if $cygwin; then 202 | # Remove spaces from KOTLIN_HOME on windows 203 | KOTLIN_HOME=`cygpath --windows --short-name "$KOTLIN_HOME"` 204 | fi 205 | 206 | [ -n "$JAVA_OPTS" ] || JAVA_OPTS="-Xmx256M -Xms32M" 207 | 208 | declare -a java_args 209 | declare -a kotlin_args 210 | 211 | while [ $# -gt 0 ]; do 212 | case "$1" in 213 | -D*) 214 | java_args=("${java_args[@]}" "$1") 215 | shift 216 | ;; 217 | -J*) 218 | java_args=("${java_args[@]}" "${1:2}") 219 | shift 220 | ;; 221 | *) 222 | kotlin_args=("${kotlin_args[@]}" "$1") 223 | shift 224 | ;; 225 | esac 226 | done 227 | 228 | if [ -z "$JAVACMD" -a -n "$JAVA_HOME" -a -x "$JAVA_HOME/bin/java" ]; then 229 | JAVACMD="$JAVA_HOME/bin/java" 230 | fi 231 | 232 | declare -a kotlin_app 233 | 234 | if [ -n "$KOTLIN_RUNNER" ]; 235 | then 236 | java_args=("${java_args[@]}" "-Dkotlin.home=${KOTLIN_HOME}") 237 | kotlin_app=("${KOTLIN_HOME}/lib/kotlin-runner.jar" "org.jetbrains.kotlin.runner.Main") 238 | else 239 | [ -n "$KOTLIN_COMPILER" ] || KOTLIN_COMPILER=org.jetbrains.kotlin.cli.jvm.K2JVMCompiler 240 | java_args=("${java_args[@]}" "-noverify") 241 | kotlin_app=("${KOTLIN_HOME}/lib/kotlin-preloader.jar" "org.jetbrains.kotlin.preloading.Preloader" "-cp" "${KOTLIN_HOME}/lib/kotlin-compiler.jar" $KOTLIN_COMPILER) 242 | fi 243 | 244 | "${JAVACMD:=java}" $JAVA_OPTS "${java_args[@]}" -cp "${kotlin_app[@]}" "${kotlin_args[@]}" 245 | ``` 246 | 247 | 我们可以看出,kotlinc是直接依赖java命令的,所以,使用Kotlin Compiler,首先要有JDK环境。 248 | 249 | 其中kotlin-preloader.jar、kotlin-compiler.jar是其入口依赖jar,入口类是org.jetbrains.kotlin.cli.jvm.K2JVMCompiler。 250 | 251 | kotlin命令脚本如下 252 | 253 | ```bash 254 | export KOTLIN_RUNNER=1 255 | 256 | DIR="${BASH_SOURCE[0]%/*}" 257 | : ${DIR:="."} 258 | 259 | "${DIR}"/kotlinc "$@" 260 | ``` 261 | 262 | 我们可以看出,直接是依赖kotlinc。在if逻辑代码中: 263 | 264 | ```bash 265 | if [ -n "$KOTLIN_RUNNER" ]; 266 | then 267 | java_args=("${java_args[@]}" "-Dkotlin.home=${KOTLIN_HOME}") 268 | kotlin_app=("${KOTLIN_HOME}/lib/kotlin-runner.jar" "org.jetbrains.kotlin.runner.Main") 269 | ``` 270 | 从这个逻辑,我们可以看出,Kt.class在java命令执行前,需要从kotlin-runner.jar这个逻辑里走一遍。同时,我们也能知道Kt.class跟Java.class文件有着这个kotlin-runner.jar的逻辑映射上的区别。也就是说,Kotlin的Bytecode跟纯的JVM bytecode存在一个kotlin-runner.jar的映射关系。其大致执行过程如下图所示: 271 | 272 | ![Kotlin极简教程](images/kotlin3.png) 273 | 274 | 像scala,groovy等基于JVM的语言的compiler,runner,基本都采用这种运行方式。在实现细节上也许会有不同,总的思路是一致的。比如说,scalac的入口类 275 | 276 | ``` 277 | https://github.com/EasyKotlin/scala/blob/2.12.x/src/compiler/scala/tools/nsc/Main.scala 278 | 279 | ``` 280 | 对应scalac中的命令行脚本是: 281 | 282 | ```bash 283 | ... 284 | 285 | execCommand \ 286 | "${JAVACMD:=java}" \ 287 | $JAVA_OPTS \ 288 | "${java_args[@]}" \ 289 | "${classpath_args[@]}" \ 290 | -Dscala.home="$SCALA_HOME" \ 291 | $OVERRIDE_USEJAVACP \ 292 | "$EMACS_OPT" \ 293 | $WINDOWS_OPT \ 294 | scala.tools.nsc.Main "$@" 295 | 296 | ... 297 | ``` 298 | 我们解压完kotlin-compiler-1.1.2-2.zip,放到相应的目录下。然后配置系统环境变量: 299 | ``` 300 | export KOTLIN_HOME=/Users/jack/soft/kotlinc 301 | export PATH=$PATH:$KOTLIN_HOME/bin 302 | ``` 303 | 304 | 执行`source ~/.bashrc`, 命令行输入`kotlinc`, 即可REPL环境,我们可以看到如下输出: 305 | 306 | ```bash 307 | $ kotlinc 308 | Welcome to Kotlin version 1.1.2-2 (JRE 1.8.0_40-b27) 309 | Type :help for help, :quit for quit 310 | >>> println("Hello,World") 311 | Hello,World 312 | >>> 313 | ``` 314 | 315 | 然后,我们就可以像使用python,ruby,scala,groovy的REPL一样去尽情享受Kotlin的编程乐趣了。 316 | 317 | 318 | ### 1.2.3 使用IntelliJ IDEA 319 | 320 | 最新版本的IDEA已经默认集成了Kotlin环境。 321 | 322 | 我们首先去下载安装IntelliJ IDEA。下载页面是: 323 | 324 | https://www.jetbrains.com/idea/download/index.html 325 | 326 | 如果您之前没用过IDEA,现在想尝试一下,可以去下面这个页面了解一下: 327 | 328 | https://www.jetbrains.com/idea/documentation/ 329 | 330 | 安装完毕,然后点击`File > New > Project`, 我们可以选择 331 | 332 | > Koltin: Kotlin(JVM), Kotlin(JavaScript) 333 | 334 | 如下图所示 335 | 336 | ![](images/kotlin4.png) 337 | 338 | 也可以选择Maven,Gradle构建工程。本书采用Gradle来构建工程。如下图所示: 339 | 340 | ![](images/kotlin5.png) 341 | 342 | 然后按照后续步骤操作,最后等待Gradle下载依赖,完成工程构建。我们将得到一个标准的Gradle工程。 343 | 344 | ![](images/kotlin6.png) 345 | 346 | 我们在`src/main/kotlin`下面新建`package` :com.easy.kotlin.chapter1 347 | 348 | 然后新建HelloWorld.kt,编写以下代码 349 | 350 | ```kotlin 351 | package com.easy.kotlin.chapter1 352 | 353 | fun main(args:Array){ 354 | println("Hello,World!") 355 | } 356 | ``` 357 | 358 | 右击运行该类,如下图 359 | 360 | ![](images/kotlin7.png) 361 | 362 | 我们将会得到输出 363 | 364 | ![](images/kotlin8.png) 365 | 366 | 我们观察IDEA控制台输出的执行日志,可以看出IDEA集成Kotlin环境使用的核心依赖jar包: 367 | 368 | ``` 369 | /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=65404:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/jre/lib/deploy.jar:... 370 | ... 371 | 372 | .../kotlin-stdlib-jre8-1.1.1.jar: 373 | .../kotlin-stdlib-jre7-1.1.1.jar: 374 | .../kotlin-stdlib-1.1.1.jar:... com.easy.kotlin.chapter1.HelloWorldKt 375 | ... 376 | 377 | 378 | Hello,World! 379 | 380 | Process finished with exit code 0 381 | ``` 382 | 383 | 本小节的示例工程代码:https://github.com/EasyKotlin/easy_kotlin_chaptor_1 384 | 385 | ### 1.2.4 使用Eclipse 386 | 387 | 使用Eclipse的开发者们,可以通过安装Kotlin插件来进行Kotlin程序的开发。但是,体验上要比使用IDEA逊色很多。如果您想完美体验Kotlin在IDE中的开发,强烈建议使用IDEA。JetBrains自家的东西,自然是比Eclipse支持的要好很多。 388 | 389 | 我们下面简单介绍一下在Eclipse中开发Kotlin程序的方法。 390 | 391 | 首先,打开`Help > Eclipse Marketplace`, 如下图 392 | 393 | ![Kotlin极简教程](images/kotlin9.png) 394 | 395 | 在搜索框里输入`Kotlin` , 将得到如下结果 396 | 397 | ![Kotlin极简教程](images/kotlin10.png) 398 | 399 | 点击`Install`, 等待完成安装,重启Eclipse。 400 | 401 | 然后,选择`Kotlin Perspective` , 如下图 402 | 403 | ![Kotlin极简教程](images/kotlin11.png) 404 | 405 | ![Kotlin极简教程](images/kotlin12.png) 406 | 407 | 点击OK。下面我们就可以新建 `Kotlin` 工程了。如下图 408 | 409 | ![Kotlin极简教程](images/kotlin13.png) 410 | 411 | 新建完工程,我们将得到如下结构的工程 412 | 413 | ![Kotlin极简教程](images/kotlin14.png) 414 | 415 | 我们可以看出,`kotlin-runtime.jar`, `kotlin-reflect.jar`,`kotlin-script-runtime.jar` 被加到了工程依赖库里。 416 | 417 | 这个配置是在`.classpath`, `.project` 配置的。当然这些配置依赖库,执行程序等等的工作是由Eclipse Kotlin插件完成的。 418 | 419 | 我们在`src`目录新建一个`package` : easy_kotlin_chatper_1 420 | 421 | 然后在此`package`下面新建一个`HelloWorld.kt`源码文件,内容如下 422 | 423 | ```kotlin 424 | package easy_kotlin_chatper_1 425 | 426 | fun main(args: Array){ 427 | println("Hello,Kotlin!") 428 | } 429 | ``` 430 | 431 | 如下图 432 | 433 | ![Kotlin极简教程](images/kotlin15.png) 434 | 435 | 右击`HelloWorld.kt`源码文件,如下图运行 436 | 437 | ![Kotlin极简教程](images/kotlin16.png) 438 | 439 | 如果一切正常,我们将得到如下输出 440 | 441 | ``` 442 | Hello,Kotlin! 443 | ``` 444 | 445 | 本节示例工程源码:https://github.com/EasyKotlin/easy_kotlin_chatper_1 446 | 447 | ### 1.2.5 使用Gradle构建Kotlin工程 448 | 449 | 我们在上面小节中展示了使用IntelliJ IDEA建立一个Kotlin Gradle工程的步骤。我们在本节简单介绍一下使用Gradle构建Kotlin工程的配置。这个配置主要在build.gradle文件中。 450 | 451 | 其中,构建过程的核心依赖配置如下: 452 | 453 | ```gradle 454 | buildscript { 455 | ext.kotlin_version = '1.1.1' 456 | 457 | repositories { 458 | mavenCentral() 459 | } 460 | dependencies { 461 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 462 | } 463 | } 464 | ``` 465 | kotlin-gradle-plugin完成了Gradle构建Kotlin工程的所有依赖构建执行的相关工作。 466 | 467 | 然后,使用Gradle java、kotlin插件: 468 | 469 | ```gradle 470 | apply plugin: 'java' 471 | apply plugin: 'kotlin' 472 | ``` 473 | 474 | 当然,如果我们同时想使用Groovy语言,加上 475 | 476 | ```gradle 477 | apply plugin: 'groovy' 478 | ``` 479 | 480 | 源代码JDK兼容性配置兼容1.8往后的版本: 481 | ```gradle 482 | sourceCompatibility = 1.8 483 | ``` 484 | 485 | 配置Maven仓库: 486 | 487 | ```gradle 488 | repositories { 489 | mavenCentral() 490 | } 491 | ``` 492 | 493 | 工程依赖: 494 | 495 | ```gradle 496 | dependencies { 497 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" 498 | compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version" 499 | compile 'org.codehaus.groovy:groovy-all:2.3.11' 500 | testCompile group: 'junit', name: 'junit', version: '4.12' 501 | } 502 | 503 | ``` 504 | 其中,kotlin-stdlib-jre8是Kotlin JVM执行环境依赖。 505 | 506 | org.jetbrains.kotlin:kotlin-stdlib-js是Kotlin JS执行环境依赖。 507 | 508 | 我们可以通过Gradle项目的依赖树看出kotlin-stdlib-jre8依赖 509 | 510 | >org.jetbrains.kotlin:kotlin-stdlib:1.1.1 511 | 512 | 如下图 513 | 514 | ![](images/kotlin17.png) 515 | 516 | kotlin-stdlib是Kotlin运行环境的标准库。 517 | 518 | ### 1.2.6 编程语言学习小结 519 | 520 | 学习一门语言大概会经历如下几步。 521 | 522 | 1.基本语法 523 | 524 | 学习任何东西,都是一个由表及里的过程。学习一门编程语言也一样。对于一门编程语言来说,“表” 就是基本词汇和语法。 525 | 526 | 对于基础语法的学习,我们可以看一些简短而又系统的教程。 527 | 528 | 2.编码实践 529 | 530 | 所谓“纸上得来终觉浅,绝知此事要躬行”是也。此处就不多说。 531 | 532 | > 掌握基础,持续练习 533 | 534 | 每一门编程语言的学习内容都会涉及: 535 | 536 | - 运行环境 537 | - 数据类型(数字、字符串、数组、集合、映射字典等) 538 | - 表达式 539 | - 函数 540 | - 流程控制 541 | - 类、方法 542 | 543 | 等等,不同的语言还有一些不同的特性,可以通过对比学习来加深理解。并通过大量实践深入理解,达到熟练使用。后面还要再去深入了解面向对象编程OOP、函数式编程FP、并发、异常、文件IO、网络、标准库等内容,并辅以持续的练习,这些内容才能够让你真正进入编程领域并做出实际的软件。 544 | 545 | > 相信10000小时定律,No Pain, No Gain。 546 | 547 | 学习一门新的语言的时候,要利用以前所学的语言的功底,但是也要保持开放的心态。这些在认知心理学中有相应的讲述。感兴趣的读者可以去了解一下。 548 | 549 | 3.技近乎道 550 | 551 | 基础语法学习,能让你快速上手,应用实践。对技巧和坑的关注,一定程度上拓展了你的知识面。系统学习,一方面会进一步拓展你的知识面。另一方面,也有利于你语言知识结构的形成。 552 | 553 | 任何一门成熟语言,都有其特有的生态。这个生态包括: 框架,扩展包,解决方案,模式, 规范等。 554 | 555 | 在不断编码实践过程中,我们逐步熟练使用很多API库、框架,也不断踩坑填坑、看源代码、不断解决问题,不断加深对语言的理解,同时会看一些优秀的框架源代码。 556 | 557 | 如果还有精力,我们再去学习语言更底层的东西,而不仅仅停留在应用层面。如Java中的集合类实现的算法与数据结构,如JVM是如何执行Java代码的。如Java的线程和操作系统线程的关系。以及一些操作系统方面的知识。 558 | 559 | 最后,达到游刃有余的境界。这一层级,基本可入武林高手之列了。 560 | 561 | > 庖丁释刀对曰:“臣之所好者,道也,进乎技矣。始臣之解牛之时,所见无非牛者。三年之后,未尝见全牛也。方今之时,臣以神遇而不以目视,官知止而神欲行。依乎天理,批大郤,导大窾,因其固然,技经肯綮之未尝,而况大軱乎! 562 | 563 | 这里的“牛”,可以理解为我们所说的各种编程思想,编程范式,编程方法,编程技巧等等。最后,达到“运用之妙,存乎一心”之境也。 564 | 565 | 4.创造新世界 566 | 567 | > 编程的本质就是创造世界。 568 | 569 | 达到这个境界的,基本都是世界顶尖大牛了。 570 | 571 | 例如,编程语言发展史上的杰出人物(下面只是一份不完全名单): 572 | 573 | ``` 574 | 约翰·冯·诺伊曼: 操作系统概念的发起者 575 | 肯·汤普逊&丹尼斯·里奇: 发明了C和Unix 576 | 约翰·巴科斯:发明了Fortran 577 | 阿兰·库珀:开发了Visual Basic 578 | 詹姆斯·高斯林:开发了Oak,即后来的Java 579 | 安德斯·海尔斯伯格:开发了Turbo Pascal、Delphi,以及C# 580 | 葛丽丝·霍普,开发了Flow-Matic,该语言对COBOL造成了影响 581 | 肯尼斯·艾佛森:,开发了APL,并与Roger Hui合作开发了J 582 | 比尔·乔伊:发明了vi,BSD,Unix的前期作者,以及SunOS的发起人,该操作系统后来改名为Solaris 583 | 艾伦·凯:开创了面向对象编程语言,以及Smalltalk的发起人 584 | Brian Kernighan:与丹尼斯·里奇合著第一本C程序设计语言的书籍,同时也是AWK与AMPL程序设计语言的共同作者 585 | 约翰·麦卡锡:发明了LISP 586 | 比雅尼·斯特劳斯特鲁普:开发了C++ 587 | 尼克劳斯·维尔特:发明了Pascal与Modula 588 | 拉里·沃尔:创造了Perl与Perl 6 589 | 吉多·范罗苏姆:创造了Python 590 | ...... 591 | 592 | ``` 593 | 594 | 这些人,都在创造一个美妙的思维逻辑之塔,创造一个新世界。正是这些各个编程领域的引领者们,才使得我们这个世界更加美好。 595 | 596 | 小结 597 | === 598 | 599 | 本章我们简单介绍了Kotlin语言的发展过程,以及Kotlin开发环境的搭建方法。简单总结了学习一门编程语言的基本过程。我们的这本书基本是按照这个思路组织架构的。 600 | 601 | 我们将在下一章进入快速开始:Hello,World! 602 | 603 | 感谢您的阅读!恭喜您已经正式开启Kotlin世界之旅,希望本书能够帮到您的学习,哪怕是一点点启发也倍感欣慰。 604 | 605 | 本书所涉及到的示例工程代码统一放在这里:https://github.com/EasyKotlin 606 | 607 | 参考资料 608 | === 609 | 1.http://www.onboard.jetbrains.com/articles/04/10/lop/index.html 610 | 2.https://medium.com/@octskyward/why-kotlin-is-my-next-programming-language-c25c001e26e3 611 | 3.http://kotlinlang.org/docs/tutorials/command-line.html 612 | 4.http://hadihariri.com/2013/12/29/jvm-minimal-survival-guide-for-the-dotnet-developer/ -------------------------------------------------------------------------------- /10.Kotlin与Java互操作/images/Kotlin与Java互操作1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/10.Kotlin与Java互操作/images/Kotlin与Java互操作1.png -------------------------------------------------------------------------------- /10.Kotlin与Java互操作/images/Kotlin与Java互操作2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/10.Kotlin与Java互操作/images/Kotlin与Java互操作2.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_01.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_02.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_03.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_04.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_05.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_06.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_07.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_08.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_09.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_10.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_11.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_12.png -------------------------------------------------------------------------------- /11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/11.使用Kotlin集成SpringBoot开发Web服务端/images/kotlin_springboot_13.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko1.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko10.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko11.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko12.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko13.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko14.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko15.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko16.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko17.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko18.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko19.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko2.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko3.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko4.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko5.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko6.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko7.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko8.png -------------------------------------------------------------------------------- /13.使用Kotlin和Anko的Android开发/images/Anko9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/13.使用Kotlin和Anko的Android开发/images/Anko9.png -------------------------------------------------------------------------------- /14.使用 Kotlin DSL/images/dsl1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/14.使用 Kotlin DSL/images/dsl1.png -------------------------------------------------------------------------------- /14.使用 Kotlin DSL/images/dsl2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/14.使用 Kotlin DSL/images/dsl2.png -------------------------------------------------------------------------------- /14.使用 Kotlin DSL/第14章 使用 Kotlin DSL.md: -------------------------------------------------------------------------------- 1 | 第14章 使用 Kotlin DSL 2 | === 3 | 4 | 我们在前面的章节中,已经看到了 Kotlin DSL 的强大功能。例如Gradle 的配置文件 build.gradle (Groovy),以及前面我们涉及到的Gradle Script Kotlin(Kotlin)、Anko(Kotlin)等,都是 DSL。我们可以看出,使用DSL的编程风格,可以让程序更加简单干净、直观简洁。当然,我们也可以创建自己的 DSL。 5 | 6 | 本章就让我们一起来学习一下 使用 Kotlin 创建 DSL的相关内容。 7 | 8 | 我们在上一章中已经看到了在 Android 中使用下面这样的 嵌套DSL 风格的代码来替代 XML 式风格的视图文件 9 | 10 | ```kotlin 11 | UI { 12 | // AnkoContext 13 | 14 | verticalLayout { 15 | padding = dip(30) 16 | var title = editText { 17 | // editText 视图 18 | id = R.id.todo_title 19 | hintResource = R.string.title_hint 20 | } 21 | 22 | var content = editText { 23 | id = R.id.todo_content 24 | height = 400 25 | hintResource = R.string.content_hint 26 | } 27 | button { 28 | // button 视图 29 | id = R.id.todo_add 30 | textResource = R.string.add_todo 31 | textColor = Color.WHITE 32 | setBackgroundColor(Color.DKGRAY) 33 | onClick { _ -> createTodoFrom(title, content) } 34 | } 35 | } 36 | } 37 | ``` 38 | 相比 XML 风格的 DSL(XML 本质上讲也是一种 DSL),明显使用原生的编程语言(例如Kotlin)DSL 风格更加简单干净,也更加自由灵活。 39 | 40 | Kotlin DSL 的编程风格是怎样的呢?以及其背后实现的原理是怎样的呢?下面就让我一起来探讨一下。 41 | 42 | ## DSL 是什么 43 | 44 | DSL(Domain-Specific Language,领域特定语言)指的是专注于特定问题领域的计算机语言(领域专用语言)。不同于通用的计算机语言(GPL),领域特定语言只用在某些特定的领域。 比如用来显示网页的HTML语言,以及Emacs所使用的Emac LISP语言等。更加典型的例子是Gradle,它基于Ant 和 Maven,使用基于Groovy的DSL 来声明项目设置,而不是传统的XML。 45 | 46 | DSL 简单讲就是对一个特定问题 (受限的表达能力) 的方案模型的更高层次的抽象表达(领域语言),使其更加简单易懂 (容易理解的语义以及清晰的语义模型)。 47 | 48 | DSL 只是问题解决方案模型的外部封装,这个模型可能是一个 API 库,也可能是一个完整的框架等等。DSL 提供了思考特定领域问题的模型语言,这使得我们可以更加简单高效地来解决问题。DSL 聚焦一个特定的领域,简单易懂,功能极简但完备。DSL 让我们理解和使用模型更加简易。 49 | 50 | 提示:关于 DSL 的详细介绍可以参考:《领域特定语言》(Martin Fowler)这本书。 51 | 52 | ## Kotlin 的 DSL 特性支持 53 | 54 | 扩展(eXtension)特性。 55 | 56 | ## 实现一个极简的 DSL 57 | 58 | OkHttp是一个成熟且强大的网络库,在Android源码中已经使用OkHttp替代原先的HttpURLConnection。很多著名的框架例如Picasso、Retrofit也使用OkHttp作为底层框架。在这里我对OkHttp做一下简单的封装,其实封装得有点粗暴只是为了演示如何实现dsl。 59 | 60 | ```kotlin 61 | import io.reactivex.BackpressureStrategy 62 | import io.reactivex.Flowable 63 | import io.reactivex.schedulers.Schedulers 64 | import okhttp3.OkHttpClient 65 | import okhttp3.Request 66 | import okhttp3.RequestBody 67 | import okhttp3.Response 68 | import java.util.concurrent.TimeUnit 69 | 70 | class RequestWrapper { 71 | 72 | var url:String? = null 73 | 74 | var method:String? = null 75 | 76 | var body: RequestBody? = null 77 | 78 | var timeout:Long = 10 79 | 80 | internal var _success: (String) -> Unit = { } 81 | internal var _fail: (Throwable) -> Unit = {} 82 | 83 | fun onSuccess(onSuccess: (String) -> Unit) { 84 | _success = onSuccess 85 | } 86 | 87 | fun onFail(onError: (Throwable) -> Unit) { 88 | _fail = onError 89 | } 90 | } 91 | 92 | fun http(init: RequestWrapper.() -> Unit) { 93 | val wrap = RequestWrapper() 94 | 95 | wrap.init() 96 | 97 | executeForResult(wrap) 98 | } 99 | 100 | private fun executeForResult(wrap:RequestWrapper) { 101 | 102 | Flowable.create({ 103 | e -> e.onNext(onExecute(wrap)) 104 | }, BackpressureStrategy.BUFFER) 105 | .subscribeOn(Schedulers.io()) 106 | .subscribe( 107 | { resp -> 108 | wrap._success(resp.body()!!.string()) 109 | }, 110 | 111 | { e -> wrap._fail(e) }) 112 | } 113 | 114 | private fun onExecute(wrap:RequestWrapper): Response? { 115 | 116 | var req:Request? = null 117 | when(wrap.method) { 118 | 119 | "get","Get","GET" -> req =Request.Builder().url(wrap.url).build() 120 | "post","Post","POST" -> req = Request.Builder().url(wrap.url).post(wrap.body).build() 121 | "put","Put","PUT" -> req = Request.Builder().url(wrap.url).put(wrap.body).build() 122 | "delete","Delete","DELETE" -> req = Request.Builder().url(wrap.url).delete(wrap.body).build() 123 | } 124 | 125 | val http = OkHttpClient.Builder().connectTimeout(wrap.timeout, TimeUnit.SECONDS).build() 126 | val resp = http.newCall(req).execute() 127 | return resp 128 | } 129 | 130 | ``` 131 | 封装完OkHttp之后,看看如何来编写get请求 132 | ```kotlin 133 | http { 134 | 135 | url = "http://www.163.com/" 136 | 137 | method = "get" 138 | 139 | onSuccess { 140 | string -> L.i(string) 141 | } 142 | 143 | onFail { 144 | e -> L.i(e.message) 145 | } 146 | } 147 | ``` 148 | 149 | 是不是很像以前用jquery来写ajax? 150 | 151 | post请求也是类似的,只不过多了body 152 | 153 | ```kotlin 154 | var json = JSONObject() 155 | json.put("xxx","yyyy") 156 | .... 157 | 158 | val postBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),json.toString()) 159 | 160 | http { 161 | 162 | url = "https://......" 163 | 164 | method = "post" 165 | 166 | body = postBody 167 | 168 | onSuccess { 169 | string -> L.json(string) 170 | } 171 | 172 | onFail { 173 | e -> L.i(e.message) 174 | } 175 | } 176 | ``` 177 | 178 | ## 使用kotlinx.html DSL 写前端代码 179 | 180 | kotlinx.html是可在 Web 应用程序中用于构建 HTML 的 DSL。 它可以作为传统模板系统(例如JSP、FreeMarker等)的替代品。 181 | 182 | kotlinx. html 分别提供了kotlinx-html-jvm 和 kotlinx-html-js库的DSL , 用于在 JVM 和浏览器 (或其他 javascript 引擎) 中直接使用 Kotlin 代码来构建 html, 直接解放了原有的 HTML 标签式的前端代码。这样,我们 也可以使用 Kotlin来先传统意义上的 HTML 页面了。 Kotlin Web 编程将会更加简单纯净。 183 | 184 | 提示: 更多关于kotlinx.html的相关内容可以参考它的 Github 地址 :https://github.com/Kotlin/kotlinx.html 185 | 186 | 要使用 kotlinx.html 首先添加依赖 187 | 188 | ```gradle 189 | dependencies { 190 | def kotlinx_html_version = "0.6.3" 191 | compile "org.jetbrains.kotlinx:kotlinx-html-jvm:${kotlinx_html_version}" 192 | compile "org.jetbrains.kotlinx:kotlinx-html-js:${kotlinx_html_version}" 193 | ... 194 | } 195 | ``` 196 | kotlinx.html 最新版本发布在 https://jcenter.bintray.com/ 仓库上,所以我们添加一下仓库的配置 197 | ```gradle 198 | repositories { 199 | maven { url 'https://jitpack.io' } 200 | mavenCentral() 201 | jcenter() // https://jcenter.bintray.com/ 仓库 202 | maven { url "https://repo.spring.io/snapshot" } 203 | maven { url "https://repo.spring.io/milestone" } 204 | } 205 | ``` 206 | 207 | 我们来写一个极简百度首页示例。这个页面界面如下图所示 208 | 209 | ![Kotlin极简教程](images/dsl1.png) 210 | 211 | 前端 HTML 代码: 212 | 213 | ```html 214 | 215 | 216 | 217 | 218 | 219 | 220 | 百度一下 221 | 222 | 223 | 224 | 225 | 226 | 227 |
228 |
229 | ![](http://upload-images.jianshu.io/upload_images/1233356-49a0fecdc8bfa9cf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 230 |
231 | 232 |
233 | 234 | 235 |
236 |
237 | 238 | 239 | ``` 240 | 241 | 其中,dsl.css文件内容如下 242 | ```css 243 | .ipad { 244 | margin: 10px 245 | } 246 | 247 | .center { 248 | text-align: center; 249 | } 250 | ``` 251 | 252 | dsl.js 文件内容如下 253 | ```javascript 254 | $(function () { 255 | $('#baiduBtn').on('click', function () { 256 | var wd = $('#wd').val() 257 | window.open("https://www.baidu.com/s?wd=" + wd) 258 | }) 259 | }) 260 | ``` 261 | 262 | 上面我们是通常使用的 HTML+JS+CSS 的方式来写前端页面的方法。现在我们把 HTML 部分的代码用Kotlin 的 DSL kotlinx.html 来重新实现一遍。 263 | 264 | 我们首先新建 Kotlin + Spring Boot 工程,然后直接来写 Kotlin 视图类HelloDSLView,代码如下: 265 | 266 | ```kotlin 267 | package com.easy.kotlin.chapter14_kotlin_dsl.view 268 | 269 | import kotlinx.html.* 270 | import kotlinx.html.stream.createHTML 271 | import org.springframework.stereotype.Service 272 | 273 | @Service 274 | class HelloDSLView { 275 | fun html(): String { 276 | return createHTML().html { 277 | head { 278 | meta { 279 | charset = "utf-8" 280 | httpEquiv = "X-UA-Compatible" 281 | content = "IE=edge" 282 | } 283 | title("百度一下") 284 | link { 285 | href = "https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" 286 | rel = "stylesheet" 287 | } 288 | script { 289 | src = "https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js" 290 | } 291 | link { 292 | href = "dsl.css" 293 | rel = "stylesheet" 294 | } 295 | script { 296 | src = "dsl.js" 297 | } 298 | } 299 | 300 | body { 301 | div(classes = "container") { 302 | div(classes = "ipad center") { 303 | img { 304 | src = "https://www.baidu.com/img/bd_logo1.png" 305 | width = "270" 306 | height = "129" 307 | } 308 | } 309 | 310 | form(classes = "form") { 311 | input(InputType.text, classes = "form-control ipad") { 312 | id = "wd" 313 | } 314 | button(classes = "btn btn-primary form-control ipad") { 315 | id = "baiduBtn" 316 | type = ButtonType.submit 317 | text("百度一下") 318 | 319 | } 320 | } 321 | 322 | } 323 | } 324 | } 325 | } 326 | } 327 | ``` 328 | 相比之下,我们使用 DSL 的风格要比原生 HTML 要简洁优雅。关键是,我们的这个 HTML 是用 Kotlin 写的,这也就意味着,我们的 HTML 代码不再是简单的静态的前端代码了。我们完全可以直接使用后端的接口返回数据来给 HTML 元素赋值,我们也完全具备了(当然是完全超越了)诸如 JSP、Freemarker 这样的视图模板引擎的各种判断、循环等的语法功能,因为我们直接使用的是一门强大的编程语言 Kotlin 来写的 HTML 代码 。 329 | 330 | 然后,我们就可以直接在控制器层的代码里直接调用我们的 Kotlin 视图代码了: 331 | 332 | ```kotlin 333 | @Controller 334 | class HelloDSLController { 335 | @Autowired 336 | var helloDSLView: HelloDSLView? = null 337 | 338 | @GetMapping("hello") 339 | fun helloDSL(model: Model): ModelAndView { 340 | model.addAttribute("hello", helloDSLView?.html()) 341 | return ModelAndView("hello") 342 | } 343 | } 344 | ``` 345 | 346 | 为了简单起见,我们借用一下 Freemarker 来做视图解析引擎,但是它只负责原封不动地来传输我们的 Kotlin 视图代码。hello.ftl 代码如下: 347 | 348 | ``` 349 | ${hello} 350 | ``` 351 | 我们的源码目录如下 352 | 353 | ``` 354 | ── src 355 | ├── main 356 | │   ├── java 357 | │   ├── kotlin 358 | │   │   └── com 359 | │   │   └── easy 360 | │   │   └── kotlin 361 | │   │   └── chapter14_kotlin_dsl 362 | │   │   ├── Chapter14KotlinDslApplication.kt 363 | │   │   ├── controller 364 | │   │   │   └── HelloDSLController.kt 365 | │   │   └── view 366 | │   │   └── HelloDSLView.kt 367 | │   └── resources 368 | │   ├── application.properties 369 | │   ├── banner.txt 370 | │   ├── static 371 | │   │   ├── dsl.css 372 | │   │   ├── dsl.js 373 | │   │   └── hello.html 374 | │   └── templates 375 | │   └── hello.ftl 376 | └── test 377 | ├── java 378 | ├── kotlin 379 | │   └── com 380 | │   └── easy 381 | │   └── kotlin 382 | │   └── chapter14_kotlin_dsl 383 | │   └── Chapter14KotlinDslApplicationTests.kt 384 | └── resources 385 | 386 | ``` 387 | 388 | 然后,启动运行 SpringBoot 应用,浏览器访问 http://127.0.0.1:8888/hello , 我们可以看到如下输出界面: 389 | 390 | ![Kotlin极简教程](images/dsl2.png) 391 | 392 | 这就是 DSL 的精妙之处。我们后面可以尝试使用 kotlinx.html 来写Kotlin 语言的前端代码了。在做 Web 开发的时候,我们通常是使用 HTML + 模板引擎(Velocity、JSP、Freemarker 等)来集成前后端的代码,这让我们有时候感到很尴尬,要学习模板引擎的语法,还得应对 前端HTML代码中凌乱的模板引擎标签、变量等片段代码。 393 | 394 | 使用 Kotlin DSL 来写 HTML 代码的情况将完全不一样了,我们将重拾前后端集成编码的乐趣(不再是模板引擎套前端 HTML,各种奇怪的 #、<#>、${} 模板语言标签),我们直接把 更加优雅简单的 DSL 风格的HTML 代码搬到了后端,同时HTML中的元素将直接跟后端的数据无缝交互,而完成这些的只是 Kotlin(当然,相应领域的 DSL 基本语义模型还是要学习一下)。 395 | 396 | 提示:本节项目源码:https://github.com/EasyKotlin/chapter14_kotlin_dsl -------------------------------------------------------------------------------- /15.Kotlin 文件IO操作与多线程/第15章 Kotlin 文件IO操作与多线程.md: -------------------------------------------------------------------------------- 1 | 第15章 Kotlin 文件IO操作与多线程 2 | === 3 | 4 | 我们在使用 Groovy 的文件 IO 操作的时候,感觉非常便利。同样的Kotlin也有好用的文件 IO 操作的 API。同样的在 Kotlin 中对 Java 的正则表达式功能做了一些实用的扩展。还有 Kotlin 中的多线程主要也是对 Java 的多线程 API 作了一些封装。因为这些 Java 已经有了很多的基础 API,Kotlin 并没有自己再去重复实现,而是在 Java 的基础上进行了实用的功能扩展。 5 | 6 | 本章我们就来介绍Kotlin 文件 IO 操作、正则表达式以及多线程相关的内容。 7 | 8 | ## 15.1 Kotlin IO 简介 9 | 10 | Kotlin的IO操作都在kotlin.io包下。Kotlin的原则就是Java已经有的,好用的就直接使用,没有的或者不好用的,就在原有类的基础上进行封装扩展,例如Kotlin 就给 File 类写了扩展函数。这跟Groovy的扩展API 的思想是一样的。 11 | 12 | ## 15.2 终端 IO 13 | 14 | Java 超长的输出语句 System.out.println() 居然延续到了现在!同样的工作在C++里面只需要简单的 cout<< 就可以完成。当然,如果需要的话,我们可以在工程中直接封装 System.out.println() 为简单的打印方法。 15 | 16 | 在Kotlin里面很简单,只需要使用println或者print这两个全局函数即可,我们不再需要冗长的前缀。当然如果我们很怀旧,就是想用 System.out.println() ,Kotlin 依然支持直接这么使用(与 Java 无缝互操作)。 17 | 18 | ```kotlin 19 | >>> System.out.println("K") 20 | K 21 | >>> println("K") 22 | K 23 | ``` 24 | 25 | 这里的 println 函数Kotlin实现如下 26 | ```kotlin 27 | @kotlin.internal.InlineOnly 28 | public inline fun println(message: Any?) { 29 | System.out.println(message) 30 | } 31 | ``` 32 | 33 | 当然,Kotlin 也只是在 System.out.println() 的基础上进行了封装。 34 | 35 | 从终端读取数据也很简单,最基本的方法就是全局函数readLine,它直接从终端读取一行作为字符串。如果需要更进一步的处理,可以使用Kotlin提供的各种字符串处理函数来处理和转换字符串。 36 | 37 | Kotlin 的封装终端IO 的类在 stdlib/src/kotlin/io/Console.kt 源文件中。 38 | 39 | ## 15.3 文件 IO 操作 40 | 41 | Kotlin为java.io.File提供了大量好用的扩展函数,这些扩展函数主要在下面三个源文件中: 42 | 43 | - kotlin/io/files/FileTreeWalk.kt 44 | - kotlin/io/files/Utils.kt 45 | - kotlin/io/FileReadWrite.kt 46 | 47 | 同时,Kotlin 也针对InputStream、OutputStream和 Reader 等都做了简单的扩展。它们主要在下面的两个源文件中: 48 | 49 | - kotlin/io/IOStreams.kt 50 | - kotlin/io/ReadWrite.kt 51 | 52 | Koltin 的序列化直接采用的 Java 的序列化类的类型别名: 53 | ```kotlin 54 | internal typealias Serializable = java.io.Serializable 55 | ``` 56 | 57 | 下面我们来简单介绍一下 Kotlin 文件读写操作。 58 | 59 | ### 15.3.1 读文件 60 | 61 | #### 读取文件全部内容 62 | 63 | 我们如果简单读取一个文件,可以使用readText()方法,它直接返回整个文件内容。代码示例如下 64 | ```kotlin 65 | /** 66 | * 获取文件全部内容字符串 67 | * @param filename 68 | */ 69 | fun getFileContent(filename: String): String { 70 | val f = File(filename) 71 | return f.readText(Charset.forName("UTF-8")) 72 | } 73 | ``` 74 | 75 | 我们直接使用 File 对象来调用 readText 函数即可获得该文件的全部内容,它返回一个字符串。如果指定字符编码,可以通过传入参数Charset来指定,默认是UTF-8编码。 76 | 77 | 如果我们想要获得文件每行的内容,可以简单通过`split("\n")`来获得一个每行内容的数组。 78 | 79 | #### 获取文件每行的内容 80 | 81 | 我们也可以直接调用 Kotlin 封装好的readLines函数,获得文件每行的内容。readLines函数返回一个持有每行内容的 List。 82 | 83 | ```kotlin 84 | /** 85 | * 获取文件每一行内容,存入一个 List 中 86 | * @param filename 87 | */ 88 | fun getFileLines(filename: String): List { 89 | return File(filename).readLines(Charset.forName("UTF-8")) 90 | } 91 | ``` 92 | 93 | #### 直接操作字节数组 94 | 95 | 我们如果希望直接操作文件的字节数组,可以使用readBytes()。如果想使用传统的Java方式,在Kotlin 中你也可以像 Groovy 一样自如使用。 96 | 97 | ```kotlin 98 | //读取为bytes数组 99 | val bytes: ByteArray = f.readBytes() 100 | println(bytes.joinToString(separator = " ")) 101 | 102 | //直接像 Java 中的那样处理Reader或InputStream 103 | val reader: Reader = f.reader() 104 | val inputStream: InputStream = f.inputStream() 105 | val bufferedReader: BufferedReader = f.bufferedReader() 106 | ``` 107 | 108 | ### 15.3.2 写文件 109 | 110 | 和读文件类似,写入文件也很简单。我们可以写入字符串,也可以写入字节流。还可以直接使用Java的 Writer 或者 OutputStream。 111 | 112 | #### 覆盖写文件 113 | 114 | ```kotlin 115 | fun writeFile(text: String, destFile: String) { 116 | val f = File(destFile) 117 | if (!f.exists()) { 118 | f.createNewFile() 119 | } 120 | f.writeText(text, Charset.defaultCharset()) 121 | } 122 | ``` 123 | 124 | #### 末尾追加写文件 125 | ```kotlin 126 | fun appendFile(text: String, destFile: String) { 127 | val f = File(destFile) 128 | if (!f.exists()) { 129 | f.createNewFile() 130 | } 131 | f.appendText(text, Charset.defaultCharset()) 132 | } 133 | ``` 134 | 135 | 136 | ## 15.4 遍历文件树 137 | 138 | 和Groovy一样,Kotlin也提供了方便的功能来遍历文件树。遍历文件树需要调用扩展方法walk()。它会返回一个FileTreeWalk对象,它有一些方法用于设置遍历方向和深度,详情参见FileTreeWalk API 文档说明。 139 | 140 | 提示:FileTreeWalk API [文档链接](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/-file-tree-walk/) 141 | 142 | 下面的例子遍历了指定文件夹下的所有文件。 143 | 144 | ```kotlin 145 | fun traverseFileTree(filename: String) { 146 | val f = File(filename) 147 | val fileTreeWalk = f.walk() 148 | fileTreeWalk.iterator().forEach { println(it.absolutePath) } 149 | } 150 | ``` 151 | 测试代码: 152 | 153 | ```kotlin 154 | @Test fun testTraverseFileTree() { 155 | KFileUtil.traverseFileTree(".") 156 | } 157 | ``` 158 | 运行上面的测试代码,它将输出当前目录下的所有子目录及其文件。 159 | 160 | 我们还可以遍历当前文件下面所有子目录文件,存入一个 Iterator<File> 中 161 | 162 | ```kotlin 163 | fun getFileIterator(filename: String): Iterator { 164 | val f = File(filename) 165 | val fileTreeWalk = f.walk() 166 | return fileTreeWalk.iterator() 167 | } 168 | ``` 169 | 170 | 我们遍历当前文件下面所有子目录文件,还可以根据条件过滤,并把结果存入一个 Sequence 中 171 | 172 | ```kotlin 173 | fun getFileSequenceBy(filename: String, p: (File) -> Boolean): Sequence { 174 | val f = File(filename) 175 | return f.walk().filter(p) 176 | } 177 | ``` 178 | 179 | 测试代码: 180 | ```kotlin 181 | @Test fun testGetFileSequenceBy() { 182 | val fileSequence1 = KFileUtil.getFileSequenceBy(".", { 183 | it.isDirectory 184 | }) 185 | fileSequence1.forEach { println("fileSequence1: ${it.absoluteFile} ") } 186 | 187 | val fileSequence2 = KFileUtil.getFileSequenceBy(".", { 188 | it.isFile 189 | }) 190 | fileSequence2.forEach { println("fileSequence2: ${it.absoluteFile} ") } 191 | 192 | val fileSequence3 = KFileUtil.getFileSequenceBy(".", { 193 | it.extension == "kt" 194 | }) 195 | fileSequence3.forEach { println("fileSequence3: ${it.absoluteFile} ") } 196 | } 197 | ``` 198 | 在工程中运行上面的测试代码,它将会有类似下面的输出: 199 | ```kotlin 200 | ... 201 | ... 202 | 203 | fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/main/kotlin/com/easy/kotlin/fileio/KFileUtil.kt 204 | fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/main/kotlin/com/easy/kotlin/fileio/KNetUtil.kt 205 | fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/main/kotlin/com/easy/kotlin/fileio/KShellUtil.kt 206 | fileSequence3: /Users/jack/kotlin/chapter15_file_io/./src/test/kotlin/com/easy/kotlin/fileio/KFileUtilTest.kt 207 | ``` 208 | 209 | ## 15.5 网络IO操作 210 | 211 | Kotlin为java.net.URL增加了两个扩展方法,readBytes和readText。我们可以方便的使用这两个方法配合正则表达式实现网络爬虫的功能。 212 | 213 | 下面我们简单写几个函数实例。 214 | 215 | 根据 url 获取该 url 的响应 HTML函数 216 | 217 | ```kotlin 218 | fun getUrlContent(url: String): String { 219 | return URL(url).readText(Charset.defaultCharset()) 220 | } 221 | ``` 222 | 223 | 根据 url 获取该 url 响应比特数组函数 224 | 225 | ```kotlin 226 | fun getUrlBytes(url: String): ByteArray { 227 | return URL(url).readBytes() 228 | } 229 | ``` 230 | 231 | 把 url 响应字节数组写入文件 232 | 233 | ```kotlin 234 | fun writeUrlBytesTo(filename: String, url: String) { 235 | val bytes = URL(url).readBytes() 236 | File(filename).writeBytes(bytes) 237 | } 238 | ``` 239 | 240 | 下面这个例子简单的获取了百度首页的源代码。 241 | 242 | ```kotlin 243 | getUrlContent("https://www.baidu.com") 244 | ``` 245 | 246 | 下面这个例子根据 url 来获取一张图片的比特流,然后调用readBytes()方法读取到字节流并写入文件。 247 | 248 | ```kotlin 249 | writeUrlBytesTo("图片.jpg", "http://n.sinaimg.cn/default/4_img/uplaod/3933d981/20170622/2fIE-fyhfxph6601959.jpg") 250 | ``` 251 | 252 | 在项目相应文件夹下我们可以看到下载好的 “图片.jpg” 。 253 | 254 | ## 15.6 kotlin.io标准库 255 | 256 | Kotlin 的 io 库主要是扩展 Java 的 io 库。下面我们简单举几个例子。 257 | 258 | #### `appendBytes` 259 | 260 | 追加字节数组到该文件中 261 | 262 | 方法签名: 263 | ```kotlin 264 | fun File.appendBytes(array: ByteArray) 265 | ``` 266 | 267 | #### `appendText` 268 | 269 | 追加文本到该文件中 270 | 271 | 方法签名: 272 | ```kotlin 273 | fun File.appendText( 274 | text: String, 275 | charset: Charset = Charsets.UTF_8) 276 | ``` 277 | 278 | #### `bufferedReader` 279 | 280 | 获取该文件的BufferedReader 281 | 282 | 方法签名: 283 | ```kotlin 284 | fun File.bufferedReader( 285 | charset: Charset = Charsets.UTF_8, 286 | bufferSize: Int = DEFAULT_BUFFER_SIZE 287 | ): BufferedReader 288 | ``` 289 | #### `bufferedWriter` 290 | 291 | 获取该文件的BufferedWriter 292 | 293 | 方法签名: 294 | ```kotlin 295 | fun File.bufferedWriter( 296 | charset: Charset = Charsets.UTF_8, 297 | bufferSize: Int = DEFAULT_BUFFER_SIZE 298 | ): BufferedWriter 299 | ``` 300 | 301 | #### `copyRecursively` 302 | 303 | 复制该文件或者递归复制该目录及其所有子文件到指定路径,如果指定路径下的文件不存在,会自动创建。 304 | 305 | 方法签名: 306 | ```kotlin 307 | fun File.copyRecursively( 308 | target: File, 309 | overwrite: Boolean = false, // 是否覆盖。true:覆盖之前先删除原来的文件 310 | onError: (File, IOException) -> OnErrorAction = { _, exception -> throw exception } 311 | ): Boolean 312 | ``` 313 | 314 | - [提示: Kotlin 对 File 的扩展函数 API 文档](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-file/index.html) 315 | - [关于 kotlin.io 下面的API文档在这里](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/index.html ) 316 | 317 | ## 15.7 执行Shell命令行 318 | 319 | 我们使用 Groovy 的文件 IO 操作感觉非常好用,例如 320 | 321 | ```groovy 322 | package com.easy.kotlin 323 | 324 | import org.junit.Test 325 | import org.junit.runner.RunWith 326 | import org.junit.runners.JUnit4 327 | 328 | @RunWith(JUnit4) 329 | class ShellExecuteDemoTest { 330 | @Test 331 | def void testShellExecute() { 332 | def p = "ls -R".execute() 333 | def output = p.inputStream.text 334 | println(output) 335 | def fname = "我图.url" 336 | def f = new File(fname) 337 | def lines = f.readLines() 338 | lines.forEach({ 339 | println(it) 340 | }) 341 | println(f.text) 342 | } 343 | } 344 | ``` 345 | 346 | Kotlin 中的文件 IO,网络 IO 操作跟 Groovy一样简单。 347 | 348 | 另外,从上面的代码中我们看到使用 Groovy 执行终端命令非常简单: 349 | 350 | ```groovy 351 | def p = "ls -R".execute() 352 | def output = p.inputStream.text 353 | ``` 354 | 355 | 在 Kotlin 中,目前还没有对 String 类和 Process 扩展这样的函数。其实扩展这样的函数非常简单。我们完全可以自己扩展。 356 | 357 | 首先,我们来扩展 String 的 execute() 函数。 358 | 359 | ```kotlin 360 | fun String.execute(): Process { 361 | val runtime = Runtime.getRuntime() 362 | return runtime.exec(this) 363 | } 364 | 365 | ``` 366 | 367 | 然后,我们来给 Process 类扩展一个 text函数。 368 | ```kotlin 369 | fun Process.text(): String { 370 | var output = "" 371 | // 输出 Shell 执行的结果 372 | val inputStream = this.inputStream 373 | val isr = InputStreamReader(inputStream) 374 | val reader = BufferedReader(isr) 375 | var line: String? = "" 376 | while (line != null) { 377 | line = reader.readLine() 378 | output += line + "\n" 379 | } 380 | return output 381 | } 382 | ``` 383 | 384 | 完成了上面两个简单的扩展函数之后,我们就可以在下面的测试代码中,可以像 Groovy 一样执行终端命令了: 385 | 386 | ```kotlin 387 | val p = "ls -al".execute() 388 | 389 | val exitCode = p.waitFor() 390 | val text = p.text() 391 | 392 | println(exitCode) 393 | println(text) 394 | ``` 395 | 396 | 实际上,通过之前的很多实例的学习,我们可以看出 Kotlin 的扩展函数相当实用。Kotlin 语言本身API 也大量使用了扩展功能。 397 | 398 | ## 15.8 正则表达式 399 | 400 | 我们在 Kotlin 中除了仍然可以使用 Java中的 Pattern,Matcher 等类之外,Kotlin 还提供了一个正则表达式类 kotlin/text/regex/Regex.kt ,我们通过 Regex 的构造函数来创建一个正则表达式。 401 | 402 | ### 15.8.1 构造 Regex 表达式 403 | 404 | #### 使用Regex构造函数 405 | ```kotlin 406 | >>> val r1 = Regex("[a-z]+") 407 | >>> val r2 = Regex("[a-z]+", RegexOption.IGNORE_CASE) 408 | ``` 409 | 410 | 其中的匹配选项 RegexOption 是直接使用的 Java 类 Pattern中的正则匹配选项。 411 | 412 | #### 使用 String 的 toRegex 扩展函数 413 | ```kotlin 414 | >>> val r3 = "[A-Z]+".toRegex() 415 | ``` 416 | 417 | ### 15.8.2 Regex 函数 418 | 419 | Regex 里面提供了丰富的简单而实用的函数,如下表所示 420 | 421 | | 函数名称 | 功能说明 | 422 | | ---------------------------------------- | ----------------------------------- | 423 | | matches(input: CharSequence): Boolean | 输入字符串全部匹配 | 424 | | containsMatchIn(input: CharSequence): Boolean | 输入字符串至少有一个匹配 | 425 | | matchEntire(input: CharSequence): MatchResult? | 输入字符串全部匹配,返回一个匹配结果对象 | 426 | | replace(input: CharSequence, replacement: String): String | 把输入字符串中匹配的部分替换成replacement的内容 | 427 | | replace(input: CharSequence, transform: (MatchResult) -> CharSequence): String | 把输入字符串中匹配到的值,用函数 transform映射之后的新值替换 | 428 | | find(input: CharSequence, startIndex: Int = 0): MatchResult? | 返回输入字符串中第一个匹配的值 | 429 | | findAll(input: CharSequence, startIndex: Int = 0): Sequence<MatchResult> | 返回输入字符串中所有匹配的值MatchResult的序列 | 430 | 431 | 下面我们分别就上面的函数给出简单实例。 432 | 433 | #### `matches` 434 | 435 | 输入字符串全部匹配正则表达式返回 true , 否则返回 false。 436 | 437 | ```kotlin 438 | >>> val r1 = Regex("[a-z]+") 439 | >>> r1.matches("ABCzxc") 440 | false 441 | >>> 442 | 443 | >>> val r2 = Regex("[a-z]+", RegexOption.IGNORE_CASE) 444 | >>> r2.matches("ABCzxc") 445 | true 446 | 447 | >>> val r3 = "[A-Z]+".toRegex() 448 | >>> r3.matches("GGMM") 449 | true 450 | 451 | ``` 452 | 453 | #### `containsMatchIn` 454 | 输入字符串中至少有一个匹配就返回true,没有一个匹配就返回false。 455 | 456 | ```kotlin 457 | >>> val re = Regex("[0-9]+") 458 | >>> re.containsMatchIn("012Abc") 459 | true 460 | >>> re.containsMatchIn("Abc") 461 | false 462 | ``` 463 | 464 | #### `matchEntire` 465 | 输入字符串全部匹配正则表达式返回 一个MatcherMatchResult对象,否则返回 null。 466 | 467 | ```kotlin 468 | >>> val re = Regex("[0-9]+") 469 | >>> re.matchEntire("1234567890") 470 | kotlin.text.MatcherMatchResult@34d713a2 471 | >>> re.matchEntire("1234567890!") 472 | null 473 | ``` 474 | 475 | 我们可以访问MatcherMatchResult的value熟悉来获得匹配的值。 476 | 477 | ```kotlin 478 | >>> re.matchEntire("1234567890")?.value 479 | 1234567890 480 | ``` 481 | 由于 matchEntire 函数的返回是MatchResult? 可空对象,所以这里我们使用了安全调用符号 ` ?. ` 。 482 | 483 | #### `replace(input: CharSequence, replacement: String): String` 484 | 485 | 把输入字符串中匹配的部分替换成replacement的内容。 486 | 487 | ```kotlin 488 | >>> val re = Regex("[0-9]+") 489 | >>> re.replace("12345XYZ","abcd") 490 | abcdXYZ 491 | ``` 492 | 我们可以看到,"12345XYZ"中`12345`是匹配正则表达式 `[0-9]+`的内容,它被替换成了 `abcd` 。 493 | 494 | #### `replace(input: CharSequence, transform: (MatchResult) -> CharSequence): String` 495 | 496 | 把输入字符串中匹配到的值,用函数 transform映射之后的新值替换。 497 | 498 | ```kotlin 499 | >>> val re = Regex("[0-9]+") 500 | >>> re.replace("9XYZ8", { (it.value.toInt() * it.value.toInt()).toString() }) 501 | 81XYZ64 502 | ``` 503 | 我们可以看到,`9XYZ8`中数字9和8是匹配正则表达式`[0-9]+`的内容,它们分别被transform函数映射 `(it.value.toInt() * it.value.toInt()).toString() ` 的新值 81 和 64 替换。 504 | 505 | #### `find` 506 | 507 | 返回输入字符串中第一个匹配的MatcherMatchResult对象。 508 | 509 | ```kotlin 510 | >>> val re = Regex("[0-9]+") 511 | >>> re.find("123XYZ987abcd7777") 512 | kotlin.text.MatcherMatchResult@4d4436d0 513 | >>> re.find("123XYZ987abcd7777")?.value 514 | 123 515 | ``` 516 | 517 | #### `findAll` 518 | 519 | 返回输入字符串中所有匹配的值的MatchResult的序列。 520 | 521 | ```kotlin 522 | >>> val re = Regex("[0-9]+") 523 | >>> re.findAll("123XYZ987abcd7777") 524 | kotlin.sequences.GeneratorSequence@f245bdd 525 | ``` 526 | 527 | 我们可以通过 forEach 循环遍历所以匹配的值 528 | 529 | ```kotlin 530 | >>> re.findAll("123XYZ987abcd7777").forEach{println(it.value)} 531 | 123 532 | 987 533 | 7777 534 | ``` 535 | 536 | ### 15.8.3 使用 Java 正则表达式类 537 | 538 | 除了上面 Kotlin 提供的函数之外,我们在 Kotlin 中仍然可以使用 Java 的正则表达式的 API。 539 | 540 | ```kotlin 541 | val re = Regex("[0-9]+") 542 | val p = re.toPattern() 543 | val m = p.matcher("888ABC999") 544 | while (m.find()) { 545 | val d = m.group() 546 | println(d) 547 | } 548 | ``` 549 | 上面的代码运行输出: 550 | 551 | ``` 552 | 888 553 | 999 554 | ``` 555 | 556 | ## 15.9 Kotlin 的多线程 557 | 558 | Kotlin中没有synchronized关键字。 559 | Kotlin中没有volatile关键字。 560 | Kotlin的Any类似于Java的Object,但是没有wait(),notify()和notifyAll() 方法。 561 | 562 | 那么并发如何在Kotlin中工作呢?放心,Kotlin 既然是站在 Java 的肩膀上,当然少不了对多线程编程的支持——Kotlin通过封装 Java 中的线程类,简化了我们的编码。同时我们也可以使用一些特定的注解, 直接使用 Java 中的同步关键字等。下面我们简单介绍一下使用Kotlin 进行多线程编程的相关内容。 563 | 564 | ### 15.9.1 创建线程 565 | 566 | 我们在 Java 中通常有两种方法在Java中创建线程: 567 | 568 | - 扩展Thread类 569 | - 或者实例化它并通过构造函数传递一个Runnable 570 | 571 | 因为我们可以很容易地在Kotlin中使用Java类,这两个方式都可以使用。 572 | 573 | #### 使用对象表达式创建 574 | 575 | ```kotlin 576 | object : Thread() { 577 | override fun run() { 578 | Thread.sleep(3000) 579 | println("A 使用 Thread 对象表达式: ${Thread.currentThread()}") 580 | } 581 | }.start() 582 | ``` 583 | 584 | 此代码使用Kotlin的对象表达式创建一个匿名类并覆盖run()方法。 585 | 586 | #### 使用 Lambda 表达式 587 | 下面是如何将一个Runnable传递给一个新创建的Thread实例: 588 | 589 | ```kotlin 590 | Thread({ 591 | Thread.sleep(2000) 592 | println("B 使用 Lambda 表达式: ${Thread.currentThread()}") 593 | }).start() 594 | ``` 595 | 596 | 我们在这里看不到Runnable,在Kotlin中可以很方便的直接使用上面的Lambda表达式来表达。 597 | 598 | 还有更简单的方法吗? 且看下文解说。 599 | 600 | #### 使用 Kotlin 封装的 thread 函数 601 | 602 | 例如,我们写了下面一段线程的代码 603 | ```kotlin 604 | val t = Thread({ 605 | Thread.sleep(2000) 606 | println("C 使用 Lambda 表达式:${Thread.currentThread()}") 607 | }) 608 | t.isDaemon = false 609 | t.name = "CThread" 610 | t.priority = 3 611 | t.start() 612 | ``` 613 | 后面的四行可以说是样板化的代码。在 Kotlin 中把这样的操作封装简化了。 614 | 615 | ```kotlin 616 | thread(start = true, isDaemon = false, name = "DThread", priority = 3) { 617 | Thread.sleep(1000) 618 | println("D 使用 Kotlin 封装的函数 thread(): ${Thread.currentThread()}") 619 | } 620 | ``` 621 | 622 | 这样的代码显得更加精简整洁了。事实上,thread()函数就是对我们编程实践中经常用到的样板化的代码进行了抽象封装,它的实现如下: 623 | 624 | ```kotlin 625 | public fun thread(start: Boolean = true, isDaemon: Boolean = false, contextClassLoader: ClassLoader? = null, name: String? = null, priority: Int = -1, block: () -> Unit): Thread { 626 | val thread = object : Thread() { 627 | public override fun run() { 628 | block() 629 | } 630 | } 631 | if (isDaemon) 632 | thread.isDaemon = true 633 | if (priority > 0) 634 | thread.priority = priority 635 | if (name != null) 636 | thread.name = name 637 | if (contextClassLoader != null) 638 | thread.contextClassLoader = contextClassLoader 639 | if (start) 640 | thread.start() 641 | return thread 642 | } 643 | ``` 644 | 645 | 这只是一个非常方便的包装函数,简单实用。从上面的例子我们可以看出,Kotlin 通过扩展 Java 的线程 API,简化了样板代码。 646 | 647 | ### 15.9.2 同步方法和块 648 | 649 | synchronized不是Kotlin中的关键字,它替换为@Synchronized 注解。 Kotlin中的同步方法的声明将如下所示: 650 | 651 | ```kotlin 652 | @Synchronized fun appendFile(text: String, destFile: String) { 653 | val f = File(destFile) 654 | if (!f.exists()) { 655 | f.createNewFile() 656 | } 657 | f.appendText(text, Charset.defaultCharset()) 658 | } 659 | ``` 660 | 661 | @Synchronized 注解与 Java中的 synchronized 具有相同的效果:它会将JVM方法标记为同步。 对于同步块,我们使用synchronized() 函数,它使用锁作为参数: 662 | 663 | ```kotlin 664 | fun appendFileSync(text: String, destFile: String) { 665 | val f = File(destFile) 666 | if (!f.exists()) { 667 | f.createNewFile() 668 | } 669 | 670 | synchronized(this){ 671 | f.appendText(text, Charset.defaultCharset()) 672 | } 673 | } 674 | ``` 675 | 跟 Java 基本一样。 676 | 677 | ### 15.9.3 可变字段 678 | 679 | 同样的,Kotlin没有 volatile 关键字,但是有@Volatile注解。 680 | 681 | ```kotlin 682 | @Volatile private var running = false 683 | fun start() { 684 | running = true 685 | thread(start = true) { 686 | while (running) { 687 | println("Still running: ${Thread.currentThread()}") 688 | } 689 | } 690 | } 691 | 692 | fun stop() { 693 | running = false 694 | println("Stopped: ${Thread.currentThread()}") 695 | } 696 | ``` 697 | 698 | @Volatile会将JVM备份字段标记为volatile。 699 | 700 | 当然,在 Kotlin 中我们有更好用的协程并发库。在代码工程实践中,我们可以根据实际情况自由选择。 701 | 702 | ## 本章小结 703 | 704 | Kotlin 是一门工程实践性很强的语言,从本章介绍的文件IO、正则表达式以及多线程等内容中,我们可以领会到 Kotlin 的基本原则:充分使用已有的 Java 生态库,在此基础之上进行更加简单实用的扩展,大大提升程序员们的生产力。从中我们也体会到了Kotlin 编程中的极简理念——不断地抽象、封装、扩展,使之更加简单实用。 705 | 706 | 本章示例代码:https://github.com/EasyKotlin/chapter15_file_io 707 | 708 | 另外,笔者综合了本章的内容,使用 SpringBoot + Kotlin 写了一个简单的图片爬虫 Web 应用,感兴趣的读者可参考源码:https://github.com/EasyKotlin/chatper15_net_io_img_crawler 709 | 710 | 在下一章,也我们的最后一章中,让我们脱离 JVM,直接使用 Kotlin Native 来开发一个直接编译成机器码运行的 Kotlin 应用程序。 -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_01.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_02.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_03.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_04.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_05.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_06.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_07.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/images/kotlin_native_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackChan1999/EasyKotlin/b7ca222eda139073d8c2f84f8a0da0d644c2c5a3/16.使用 Kotlin Native/images/kotlin_native_08.png -------------------------------------------------------------------------------- /16.使用 Kotlin Native/第16章 使用 Kotlin Native.md: -------------------------------------------------------------------------------- 1 | 第16章 使用 Kotlin Native 2 | === 3 | 4 | 不得不说 JetBrains 是一家务实的公司,各种IDE让人赞不绝口,用起来也是相当溜。同样的,诞生自 JetBrains 的 Kotlin 也是一门务实的编程语言,Kotlin以工程实用性为导向,充分借鉴了Java, Scala, Groovy, C#, Gosu, JavaScript, Swift等等语言的精华,让我们写起代码来可谓是相当优雅却又不失工程质量与效率。Kotlin Native能把 Kotlin代码直接编译成机器码,也就是站在了跟 C/C++、Go和Rust的同一个层次,于是这个领域又添一位竞争对手。 5 | 6 | 在前面的所有章节中,我们使用的 Kotlin 都是基于 JVM 的运行环境。本章我们将从 JVM 的运行环境中离开,走向直接编译生成原生机器码的系统编程的生态系统:Kotlin Native 。 7 | 8 | ## 16.1 Kotlin Native 简介 9 | 10 | Kotlin Native利用LLVM来编译到机器码。Kotlin Native 主要是基于 LLVM后端编译器(Backend Compiler)来生成本地机器码。 11 | 12 | Kotlin Native 的设计初衷是为了支持在非JVM虚拟机平台环境的编程,如 ios、嵌入式平台等。同时支持与 C 互操作。 13 | 14 | ### 16.1.1 LLVM 15 | 16 | LLVM最初是Low Level Virtual Machine的缩写,定位是一个虚拟机,但是是比较底层的虚拟机。LLVM是构架编译器(compiler)的框架系统,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间(compile-time)、链接时间(link-time)、运行时间(run-time)以及空闲时间(idle-time),对开发者保持开放,并兼容已有脚本。 17 | 18 | LLVM的出现正是为了解决编译器代码重用的问题,LLVM一上来就站在比较高的角度,制定了LLVM IR这一中间代码表示语言。LLVM IR充分考虑了各种应用场景,例如在IDE中调用LLVM进行实时的代码语法检查,对静态语言、动态语言的编译、优化等。 19 | 20 | ### 16.1.2 支持平台 21 | 22 | Kotlin Native现在已支持以下平台: 23 | 24 | | 平台名称 | target 配置 | 25 | | ------------- | ------------- | 26 | | Linux | linux | 27 | | Mac OS | macbook | 28 | | Windows | mingw | 29 | | Android arm32 | android_arm32 | 30 | | Android arm64 | android_arm64 | 31 | | iOS | iphone | 32 | | Raspberry Pi | raspberrypi | 33 | 34 | 这意味着我们可以在这些平台上愉快地开始体验了!目前Kotlin Native 已经发布的最新预发布版本是 v0.3 。 35 | 36 | ### 16.1.3 解释型语言与编译型语言 37 | 38 | 编译型语言,是在程序执行之前有一个单独的编译过程,将程序翻译成机器语言,以后执行这个程序的时候,就不用再进行翻译了。例如,C/C++ 等都是编译型语言。 39 | 40 | 解释型语言,是在运行的时候将程序翻译成机器语言,所以运行速度相对于编译型语言要慢。例如,Java,C#等都是解释型语言。 41 | 42 | 虽然Java程序在运行之前也有一个编译过程,但是并不是将程序编译成机器语言,而是将它编译成字节码(可以理解为一个中间语言)。在运行的时候,由JVM将字节码再翻译成机器语言。 43 | 44 | ## 16.2 快速开始 Hello World 45 | 46 | ### 16.2.1 运行环境准备 47 | 48 | 我们直接去 Github上面去下载 kotlin-native 编译器的软件包。下载地址是 :https://github.com/JetBrains/kotlin-native/releases 49 | 50 | ![Kotlin极简教程](images/kotlin_native_01.png) 51 | 52 | 下载解压之后,我们可以看到 Kotlin Native 编译器 konan 的目录如下: 53 | ``` 54 | -rw-r--r--@ 1 jack staff 6828 6 20 22:47 GRADLE_PLUGIN.md 55 | -rw-r--r--@ 1 jack staff 16286 6 20 22:47 INTEROP.md 56 | -rw-r--r--@ 1 jack staff 1957 6 21 01:03 README.md 57 | -rw-r--r--@ 1 jack staff 4606 6 20 22:47 RELEASE_NOTES.md 58 | drwxr-xr-x@ 8 jack staff 272 6 20 23:04 bin 59 | drwxr-xr-x 6 jack staff 204 7 28 17:08 dependencies 60 | drwxr-xr-x@ 3 jack staff 102 6 20 23:01 klib 61 | drwxr-xr-x@ 5 jack staff 170 5 12 00:02 konan 62 | drwxr-xr-x@ 4 jack staff 136 5 12 00:02 lib 63 | drwxr-xr-x@ 22 jack staff 748 6 22 19:04 samples 64 | ``` 65 | 66 | 关于这个目录里面的内容我们在后面小节中介绍。 67 | 68 | 另外,我们也可以自己下载源码编译,这里就不多说了。 69 | 70 | ### 16.2.2新建 Gradle 工程 71 | 72 | 在本小节中,我们先来使用IDEA 来创建一个普通的 Gradle 工程。 73 | 74 | 第1步,打开 File -> New -> Project ,如下图所示 75 | 76 | ![Kotlin极简教程](images/kotlin_native_02.png) 77 | 78 | 第2步,新建Gradle项目。我们直接在左侧栏中选择 Gradle,点击 Next 79 | 80 | ![Kotlin极简教程](images/kotlin_native_03.png) 81 | 82 | 第3步,设置项目的 GroupId、ArtifactId、Version 信息 83 | 84 | ![Kotlin极简教程](images/kotlin_native_04.png) 85 | 86 | 第4步,配置 Gradle 项目的基本设置。我们直接选择本地的 Gradle 环境目录,省去下载的时间(有时候网络不好,要下载半天),具体配置如下图所示 87 | 88 | ![Kotlin极简教程](images/kotlin_native_05.png) 89 | 90 | 第5步,配置项目名称和项目存放目录,点击 Finish 91 | 92 | ![Kotlin极简教程](images/kotlin_native_06.png) 93 | 94 | 第6步,等待 IDEA 创建完毕,我们将得到一个如下的Gradle 工程 95 | 96 | ![Kotlin极简教程](images/kotlin_native_07.png) 97 | 98 | 现在这个工程里面什么都没有。下面我们就来开始原始的手工新建文件编码。 99 | 100 | ### 16.2.3 源代码目录 101 | 102 | 首先我们在工程根目录下面新建 src 目录,用来存放源代码。在 src 下面新建 c 目录存放 C 代码,新建 kotlin 目录存放 Kotlin 代码。我们的源代码组织结构设计如下 103 | 104 | ``` 105 | src 106 | ├── c 107 | │   ├── cn_kotlinor.c 108 | │   ├── cn_kotlinor.h 109 | └── kotlin 110 | └── main.kt 111 | 112 | ``` 113 | 114 | ### 16.2.4 C 代码文件 115 | 116 | #### cn_kotlinor.h 117 | 118 | C头文件中声明如下 119 | 120 | ```c 121 | #ifndef CN_KOTLINOR_H 122 | #define CN_KOTLINOR_H 123 | void printHello(); 124 | int factorial(int n); 125 | int fib(int n); 126 | #endif 127 | ``` 128 | 我们简单声明了3个函数。 129 | 130 | #### cn_kotlinor.c 131 | 132 | C 源代码文件内容如下 133 | ```c 134 | #include "cn_kotlinor.h" 135 | #include 136 | 137 | void printHello(){ 138 | printf("[C]HelloWorld\n"); 139 | } 140 | 141 | int factorial(int n){ 142 | printf("[C]calc factorial: %d\n", n); 143 | if(n == 0) return 1; 144 | return n * factorial(n - 1); 145 | } 146 | 147 | int fib(int n){ 148 | printf("[C]calc fibonacci: %d\n", n); 149 | if(n==1||n==2) return 1; 150 | return fib(n-1) + fib(n-2); 151 | } 152 | ``` 153 | 这就是我们熟悉的 C 语言代码。 154 | 155 | ### 16.2.5 Kotlin 代码文件 156 | 157 | main.kt 文件内容如下 158 | 159 | ```kotlin 160 | import ckotlinor.* 161 | 162 | fun main(args: Array) { 163 | printHello() 164 | (1..7).map(::factorial).forEach(::println) 165 | (1..7).map(::fib).forEach(::println) 166 | } 167 | ``` 168 | 169 | 其中,`import kotlinor.*` 是 C 语言代码经过 clang 编译之后的C 的接口包路径,我们将在下面的 build.gradle 配置文件中的konanInterop中配置这个路径。 170 | 171 | ### 16.2.6 konan插件配置 172 | 173 | 首先,我们在 build.gradle 里面添加构建脚本 buildscript 闭包 174 | 175 | ```gradle 176 | buildscript { 177 | repositories { 178 | mavenCentral() 179 | maven { 180 | url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies" 181 | } 182 | } 183 | dependencies { 184 | classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:0.3" 185 | } 186 | } 187 | ``` 188 | 189 | 这里我们添加了Gradle 构建 Kotlin Native 工程的 DSL 插件 kotlin-native-gradle-plugin:0.3 。这里的版本号,对应我们下载的 konan 编译器的版本号,我们使用的是 v0.3,所以这里我们也使用0.3版本的插件。这个插件发布在https://dl.bintray.com/jetbrains/kotlin-native-dependencies仓库里,所以我们在repositories里面添加了这个仓库。 190 | 191 | 然后,我们应用插件 konan 192 | 193 | ```gradle 194 | apply plugin: 'konan' 195 | ``` 196 | konan 就是用来编译 Kotlin 为 native 代码的插件。 197 | 198 | ### 16.2.7 konanInterop 互操作配置 199 | 200 | ``` 201 | konanInterop { 202 | ckotlinor { 203 | defFile 'kotlinor.def' // interop 的配置文件 204 | includeDirs "src/c" // C 头文件目录,可以传入多个 205 | } 206 | } 207 | ``` 208 | konanInterop 主要用来配置 Kotlin 调用 C 的接口。konanInterop 的配置是由konan 插件API中的 KonanInteropTask.kt来处理的([这个类的源码地址](https://github.com/JetBrains/kotlin-native/blob/master/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropTask.kt))。 209 | 210 | 这里我们声明的 ckotlinor 是插件中的KonanInteropConfig 对象。我们在下面的konanArtifacts里面会引用这个 ckotlinor 。 211 | 212 | 关于konanInterop的配置选项有 213 | 214 | ``` 215 | konanInterop { 216 | pkgName { 217 | defFile 218 | pkg 219 | target 220 | compilerOpts 221 | linkerOpts 222 | headers 223 | includeDirs 224 | linkFiles 225 | dumpParameters