其次,我们在认识到一点,就可以看见这门语言的兼容性!

Kotlin能够和Java达到100%互通,也就是说,使用Kotlin依旧可以调用 Java已有的代码或库,也可以同时使用Java和Kotlin来混合编写代码。

最后,Kotlin中的很多语法的规范性和安全性都得到了质的提高,同时,其语法的难易度也下降了很多,学习过Java的基本上入门Kotlin也是非常友好的!

我对Kotlin初步的看法是什么呢?

代码简短,很多语法糖有python的影子,格式也类似

思想典型,面向对象的思想基本和Java可以一一对应

美观易懂,在lambda上的精简程度可以说是完美

......

Kotlin有很多优点,而学习它能过在未来的编程过程中打下坚实的基础!

2、如何创建Kotlin项目?

无论是IDEA还是Android Studio,都是可以直接编辑Kotlin代码的。

目前Spring boot框架已经兼容了Kotlin,并且可以创建Kotlin项目

Android开发也可以使用Kotlin来进行app的编写

我这里使用IDEA来举例子:

新建一个项目

创建Kotlin项目

一路next就完事了

最后需要等待gradle的第一次构建(需要比较长的时间,耐心等待一下)

3、hello world

使用Kotlin简简单单的写一个 hello world

fun main(args: Array<String>) {
   println("hello world!")
}

上面的方法和Java中的如下代码是一样的

public class test {
   public static void main(String[] args) {
       System.out.println("hello world!");
  }
}

和Java的区别:

不必用分号结束

参数使用 参数名: 参数类型 的方式

main方法不需要写在一个class中

4、Kotlin控制台的输入输出

入门一门语言,最开始学习都是这样的流程

输出 “输入姓名”

通过控制台输入...

输出 “你的姓名是XXX”

很多人都喜欢使用如上的方法来接触一门语言中最基本的方法(函数),如果想利用Kotlin来进行控制台交互,那么可以如此:

使用 println() 或者 print() 来进行输出

使用 readLine() 来进行控制台输入

导入 Java的Scanner 来进行控制台输入

我们来演示一个最简单的例子

fun main() {
   println("请输入你的姓名:")
   val name = readLine()
   println("请输入你的年龄:")
   val scanner = Scanner(System.`in`)
   val age = scanner.nextInt()
   println("你的姓名是:$name")
   println("你的年龄是:$age")
}

/*
   请输入你的姓名:
   woodwhale
   请输入你的年龄:
   19
   你的姓名是:woodwhale
   你的年龄是:19

   进程已结束,退出代码0
*/

4、Kotlin中的变量与常量

1.可读写变量var

可读写变量在Kotlin中使用关键字 var 来表示,我们可以理解为 一个具有getter和setter的private属性对象

格式就是: var 变量名:变量类型 = 赋值

var value:Int = 1

当然,kotiln很智能,可以推断出当前这个变量是什么类型的,所以上面的赋值我们可以简写为:

var value = 1

上面这个情况是整数,而我们知道,除了int类型,大部分语言中还有其他的数字数据类型,Kotlin中有如下几种基本的数据类型:

Short(16位)

Int(32位)(默认推断)

Long(64位)

不同的数据类型可以通过 toXX() 方法来转换,并且Kotlin不会Java一样,自动装箱拆箱,无法直接将一个Int类型值转为Long类型,需要调用 toLong() 方法来转换

从较大的类型转换为较小的类型可能会 截断该值 ,例如Long转为Byte

将上述的各个变量都使用Kotlin写一遍

fun main() {
   // 整型
   var oneShort:Short = 1
   var twoInt:Int = 1
   var threeLong:Long = 1
   // 浮点型
   var fourFloat:Float = 4.0f
   var fiveDouble:Double = 5.0
   // 字节
   var sixByte:Byte = 6
   // 字符
   var sevenChar:Char = '7'
   var eightString:String = "8"
   // 布尔型
   var flag:Boolean = true;
}

值得一提的是String变量使用了python中的三个引号的方式来声明变量,可以支持换行

fun main() {
   var longString = """
       oneLine
       twoLine
       threeLine
   """.trimIndent()
   println("my input : \n$longString")
}

如果上述代码没有 trimIndent() 方法,那么连tab缩减也会一并打印出来

细心的你还发现了一个 $ 符号,其实这是Kotlin的一个特性,可以用 $ 来指代变量(或者常量)

如果你想仅仅打出 $ 这个符号,只需要加一个转义字符 \ 到前面就可以了 \$

println("\$longString") // 这样输出的就是 $longString

2.可读不可写变量val

可读但是不可写的变量使用关键字 val 来修饰,我们可以把它理解成一个具有getter但是没setter的private对象

也就是说,val修饰的变量是只能读的,一旦申明就无法更改了

值得注意的是,Kotlin官方建议: 能用val处理的变量尽量不要用var来处理

这里就不多细讲了,就是上述的var没有第二次更改的权限的一种变量

3.编译器常量const val

使用const val修饰的是常量,是在编译时期就会进行初始化的常量,我们可以理解为Java中public static final修饰的一个值

一般我们使用大写的字母加上下划线来对常量赋值,并且Kotlin中常量的赋值位置有两个

top-level级别

所谓的top-level就是位于代码文件的最外部,比如常见的类(非内部类和嵌套类)就是在top-level。意思是在结构上常量不属于任何的类,而是属于文件。

// top-level
const val BASE_URL = "https://www.woodwhale.top/"

class Test {
   companion object {
       const val BASE_URL = "https://www.woodwhale.top/"
  }
}

现在还没学习到Kotlin的面向对象,所以不需要深入理解类与对象的思想

5、Kotlin中的区间和过程

区间在每个语言中都有,从最基础的for循环开始,就有区间的涉及了

Kotlin中对于区间有专门的数据对象 IntRange ,有专门的过程数据对象 IntProgression

fun rangeFun() {
   val firstRange:IntRange = 0..1
   val secondRange = 0.rangeTo(1)
   val thirdRange = 0 until 2
   val fourthRange = 0.until(2)
}
fun progressionFun() {
   val firstProgression : IntProgression= 0 .. 100  step 2
   val secondProgression = 0 until 100 step 4
}

如上述代码,第一个和第二个区间是等价的,表示 [0,1] ,第三个和第四个区间是等价的,表示 [0,2)

当然 IntRange 类型和 IntProgression 类型可以省略不写,让Kotlin自动识别

我们一般使用区间和for循环一起使用

for (i in firstRange) {
   println(i)
}
for (i in firstProgression) {
   println(i)
}

6、Kotlin中的数据容器

数据容器最常用的就几种

后三种可以统称为集合

让我们来学习Kotlin中这些数据容器的基本使用方法!

Kotlin中创建数组的方法有很多

arrayOf()方法

arrayOfNulls()方法

动态创建数组

(1) arrayOf方法创建数组

创建一个数组并且将元素初始化,数组中的元素可以是 任何类型

fun main() {
   val testArray = arrayOf(1,2,3)
   val testArray2 = arrayOf("String",'c',114,false)
}

(2) arrayOfNulls方法创建数组

创建一个 指定大小 ,元素为空的数组,必须指定元素类型

fun main() {
   val testArrayOfNulls = arrayOfNulls<String>(114)
   testArrayOfNulls[0] = "first"
   testArrayOfNulls[113] = "last"
}

(3) 动态创建数组

我们可以使用Array()类的构造方法进行动态数组的实例化,需要初始化Array对象的大小,这里使用的是10,同时可以给其中的对象使用lambda进行赋值,如下代码就是将0~9这些数据存入到了Array中

fun main() {
   // 创建一个Array<Int>初始化为[0,1,2,3,4,5,6,7,8,9]
   val testArray = Array(10){i -> i} // 使用lambda表达式
   println(testArray.joinToString())
}

/*
   0, 1, 2, 3, 4, 5, 6, 7, 8, 9
   进程已结束,退出代码0
*/

(4) 原生类型数组

在Kotlin中有无装箱开销的专门的类来表示原生数组

原生数组类型 含义 ByteArray ShortArray 短整型数组 IntArray LongArray 长整型数组 BooleanArray 布尔型数组 CharArray 字符型数组 FloatArray 浮点型数组 DoubleArray 双精度浮点数组

举个例子:

fun main() {
   // 初始化一个[0,1,2,3,4]的Int数组
   val testIntArray = IntArray(5){it}
   println(testIntArray.joinToString())
}

这里的it其实是lambda表达式中的内容,我们现在就理解为遍历这个数组时候的下标就可以了,将下标这个数字赋值给当前下标的数组内容,就可以得到[0,1,2,3,4]的Int数组啦

2.数组的遍历

我们尝试使用for循环进行数组的遍历,结合我们上面所学的 区间和过程 来完成

for循环有两种方式

普通的for循环

foreach循环

在Kotlin中,也是具有这两种循环的方式,并且结合了Java中Array.steam的优点,也具有foreach循环的方法

下面我们就来学习一下两种循环如何写!

(1) for循环下标遍历

Java 中,我们最常见的写法如下

for (int i = 0; i < someArray.length; i++) {
   doSomething()
}

很明显,这是在遍历一次数组,在 `Kotlin 中可以结合区间来写

// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it*2}
for (index in 0 until  testIntArray.size) {
   println(testIntArray[index])
}

0 until testIntArray.size 表示[0,testIntArray.size)这个区间,是不是和Java中的代码对应了呢?

但是Kotlin其实有更简单的遍历表达方式,已经帮你想好啦

// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it*2}
for (index in testIntArray.indices) {
   println(testIntArray[index])
}

使用 testIntArray.indices 属性,就可以得到当前这个数组的步频为1的区间过程啦,减少了代码量

(2) foreach元素遍历

foreach是进行元素遍历的,在 Java 中,这样的遍历如下:

for (String s in strs) {
   doSomething(s);
}

那么在 kotln 中,写法与Java类似,只不过方便了不用再写一次数据类型,Kotlin会自动推断

// 初始化一个[0,1,2,3,4]的Int数组
val testIntArray = IntArray(5){it*2}
for (intItem in testIntArray) {
   println(intItem)
}

当然了,我们不用担心存在不同元素类型的数组,我们在遍历的时候,都是可以对这些元素进行操作的

fun main() {
   val arr = arrayOf(1,"2",false,'4')
   for (item in arr) {
       when (item) {
           is Int -> println("Int type $item")
           is String -> println("String type $item")
           is Boolean -> println("Boolean type $item")
           is Char -> println("Char type $item")
      }
  }
}

/*
   Int type 1
   String type 2
   Boolean type false
   Char type 4

   进程已结束,退出代码0
*/

上述代码使用了when关键字,等到我们下一章再开始学,我们先理解其为switch就可以啦。并且,使用的is关键字表示判断item是否是某个数据类型。

在Kotlin中,还有一种 forEach()方法 ,可以进行循环使用

arr.forEach {
   when (val item = it) {
       is Int -> println("Int type $item")
       is String -> println("String type $item")
       is Boolean -> println("Boolean type $item")
       is Char -> println("Char type $item")
  }
}

如上代码的效果与我们使用经典的forEach的效果是一样的,这里的it是迭代器中当前的item

(3)foreach带上下标

Kotlin中有一种特殊的foreach,可以将index和item同时使用,减少代码量

使用 arr.withIndex() 的方法,可以带出index和item两个值,就可以同时对这两个元素进行操作

val arr = arrayOf(1,"2",false,'4')
for ( (index,item) in arr.withIndex()) {
   println("$item 's index == $index")
}
/*
   1 's index == 0
   2 's index == 1
   false 's index == 2
   4 's index == 3

   进程已结束,退出代码0
*/

同时在Kotlin中,还有一种 arr.forEachIndexed() 的方法,也可以做到index和item同时更改

arr.forEachIndexed() {
   index, item ->
   println("$item 's index == $index")
}

或者将代码写在括号内也是可以的

arr.forEachIndexed({ index, item -> println("$item 's index == $index") }) 

这些方法都是使用了lambda表达式,现在看看用法就可以了,我们之后再详细学习!

集合这种数据结构在各种工程中是必不可少的一部分。与数组不同的是 可变集合的大小是可以动态改变的

List:有序集合,可以通过下标访问元素,同一元素可以在list中 出现多次

Set:唯一元素集合,一组无重复元素的集合,一般不注重顺序,注重 是否存在

Map:键值对集合,键唯一,值可以重复,一个映射,注重 一一对应

与Java中的集合不同的是,Kotlin中的集合有可变的和不可变的,可变的集合可以动态添加元素,不可变的集合只能在初始化的时候就进行申明

(1) List的创建

我们先来创建一个可变集合,可以使用两种方法

arrayListOf < T > ()

mutableListOf < T > ()

fun main() {
   val mutableListOf = mutableListOf<String>("-1","0")
   mutableListOf.add("1")
   mutableListOf.add("2")
   mutableListOf.forEach() { println(it)}

   val arrayListOf = arrayListOf<String>()
   arrayListOf.add("3")
   arrayListOf.add("4")
   for (s in arrayListOf) { println(s)}
}

当前阶段,这两个方法返回的都是 ArrayList ,但是Kotlin官方计划将之后的mutableList与ArrayList区分开来。所以在Kotlin中咱们尽量使用mutableListOf()方法来创建list吧!

再来创建一个不可变的集合,使用方法

listOf < T > ()

val listOf = listOf<String>("1", "2", "3")
println(listOf)

注意,listOf得到的集合是 不可变 的,也就是 没有set方法,只能get!

(2) Map的创建

首先介绍Kotlin中的键值对,可以使用 Pair("key", "value") 的方式来创建,也可以简写成 "key" to "value"

可变Map的创建也有很多方法

mutableMapOf < K,V > () (返回可变的mutableMap)

hashMapOf() (返回可变的HashMap)

linkedMapOf() (返回可变的LinkedHashMap)

sortedMapOf() (返回可变的TreeMap)

可变的map可以使用 put方法 动态添加,用 get方法 获取。当然也可以使用Kotlin自己的方式,使用 下标来获取、赋值

fun main() {
   val mutableMap = mutableMapOf("key" to "value")
   mutableMap.put("key1","value1")
   mutableMap["k2"] = "v2"
   val hash = hashMapOf<String, String>("name" to "alfred")
   val linkedMap = linkedMapOf<String, String>("age" to "27")
   val treeMap = sortedMapOf("sex" to "man")

   println(mutableMap.get("key1"))
   println(hash["name"])
   println(linkedMap)
   println(treeMap)
}

那么如何删除map的key呢

使用 remove() 方法

或者使用 -

fun main() {
   val mutableMap = mutableMapOf("key" to "value")
   mutableMap.put("key1","value1")
   mutableMap["k2"] = "v2"
   mutableMap.remove("k2")
   mutableMap -= "key1"
   
   println(mutableMap)
}

不可变的Map创建的方式如下,使用 mapOf<K,V>() 方法

val mapOf = mapOf<String,String>(Pair("key", "value"))
val mapOf1 = mapOf("key" to "value")

需要注意的是,用mapOf创建的map是不可变的,所以需要在初始化的时候就申明key和value。

(3) Set的创建

和上面的集合结构一样,也是具有可变set和不可变的set

可变set的创建方式,与map类似

mutableSetOf < K,V > () (返回可变的mutableSet)

hashSetOf() (返回可变的HashSet)

linkedSetOf() (返回可变的LinkedHashSet)

sortedSetOf() (返回可变的TreeSet)

fun main() {
   val mutableSetOf = mutableSetOf("1", "2")
   mutableSetOf.remove("1")
   mutableSetOf -= "2"
   println("1" in mutableSetOf)
   println("3" in mutableSetOf)
}

不可变的set创建方式就是 setOf() 方法

fun main() {
   val of = setOf("1", "2")
   println(of)
}

(4) 集合的总结

listOf 创建不可变 List, mutableListOf() 创建可变的 List

setOf 创建不可变 Set, mutableSetOf() 创建可变 Set

mapOf 创建不可变 Map, mutableMapOf() 创建可变的 Map

mutable 前缀的函数创建是可变的集合,没有 mutable 前缀的创建不可变的集合

不可变集合可通过 toMutable*() 函数换成可变的集合,也就是创建新的可变集合并把数据放进去

7、Kotlin的更多内容

由于篇幅限制,后面更多的Kotlin语法、关键字的使用方法在下一篇文章中讲述!