Kotlin 学习笔记(1)基本语法

Kotlin 学习笔记(1)基本语法


关于 Kotlin 的安装,Android studio 3.0及以上自带,其他的可以通过搜索插件 Kotlin 来进行安装。下面来说说有关 Kotlin 的语法。

以下是本人的学习笔记,入有任何不妥之处,随时欢迎拍砖指正。
谢谢 ^_^

1. Kotlin Android 扩展

Kotlin 插件自带有安卓扩展,因此不需要再单独安装额外插件。
我们直接 new Kotlin Activity 后出现提示让配置 Kotlin



通过点击来自动导入 Kotlin 所需要的配置


实际上在项目的 Gradle上多了一行


项目 module 的 build.gradle 中多了



apply 多了


以上都是自动生成的

然后我们需要在项目 module 的 build.gradle 文件中添加以下代码

apply plugin: 'kotlin-android-extensions'

这样我们就可以用简写了,比如在 XML 中定义一个 TextView

<TextView
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"/>

我这里 ID 设置为『hello』那么我们在 Activity 中的代码就变成了

class KotlinActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_kotlin)
        hello.text = "你是不是傻"
    }
}

这样直接通过 hello.text 来设置内容,而不是原来长长的

 findView(R.id.textView) as TextView

该插件相当于把 XML 中的控件『id』作为 Activity 的额外属性来使用。

语句的结尾不用加;

简洁了很多~~

2. 定义函数

Kotlin 中所有的函数直接通过 fun 来声明。

fun sum(a: Int , b: Int) : Int{
    return a + b
}

fun sum(a: Int, b: Int) = a + b

上面两种方式都可以通过以下代码来调用。

println(sum(3, 5))
// 输出如下:
I/System.out: 8

3. 定义局部变量

var 表示变量,val 表示常量(相当于java中被final修饰)
val a: Int = 1  // 立即初始化
val b = 2   // 推导出Int型
val c: Int  // 当没有初始化值时必须声明类型
c = 3       // 赋值
println("a = $a, b = $b, c = $c")
var x = 5 // 推导出Int类型
x += 1
println(" x = $x")
// 输出如下:
I/System.out: x = 6

4. 注释

与 Java 和 JavaScript 一样,Kotlin 支持单行注释和块注释。

5. 使用字符串模板

var a = 1
// 使用变量名作为模板:
val s1 = "a is $a"
println(s1)

a = 2
// 使用表达式作为模板:
val s2 = "${s1.replace("is", "was")}, but now is $a"
println(s2)
println(s1)
// 输出如下:
I/System.out: a is 1
I/System.out: a was 1, but now is 2                   
I/System.out: a is 1

我发现在 val s2 中通过 replace 修改了 s1 的值,但是在最后的输出 s1 时,s1 的值并没有改变。
通过进入 replac 方法得知使用该方法后的字符串会重新生成新的字符串,并不改变原值O(∩_∩)O哈哈 一看就是我 Java 基础没学好~
附图:

6. 使用条件表达式

fun maxOf(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}
fun maxOf(a: Int, b: Int) = if (a > b) a else b
println("我今年${maxOf(0, 18)}岁了.")
hello.text = "我今年${maxOf(0, 18)}岁了."
// 输出如下:
I/System.out: 我今年18岁了.

以上两种方式都可以表达。

7. 使用可空变量以及空值检查

开发中最常见的错误应该就是NullPointerException了,那么 Kotlin 是怎么解决这个问题的呢?

7.1 可空类型和非空类型

Kotlin 中用 ? 来表示该变量是否可以为空。下面看实例


当我们没有明确 String 可以为空的情况下,当 String 赋予null 时,会报错,导致无法运行。

前者我们可以直接调用

val l2 = a2.length
但是后者
val l3 = a3.length

我们不可以直接调用,因为 a3 可能为空,这里我们就要用到条件表达式了

7.2 在条件中检查 null

val l3 = if (a3 != null) a3.length else -1

// 输出如下:
I/System.out: 3

或者

if (a3 != null && a3.isNotEmpty())
    println("Stirng of length ${a3.length}")
else
    println("Empty string")   
// 输出如下:
I/System.out: Stirng of length 3

7.3 安全调用

使用安全操作符,?.

a3?.length

如果 a3 不为空则返回长度,否则返回空。
这个表达式的的类型是Int?

安全调用在链式调用是是很有用的。比如,如果 Bob 是一个雇员可能分配部门(也可能不分配),如果我们想获取 Bob 的部门名作为名字的前缀,就可以这样做:

bob?.department?.head?.name

这样的调用链在任何一个属性为空都会返回空。

7.4 Elvis 操作符

使用 Elvis 操作符,?:

val l = b.length?: -1

如果 ?: 左边表达式不为空则返回,否则返回右边的表达式。注意右边的表达式只有在左边表达式为空才会返回。

7.5 !! 操作符

用 b!! ,这会返回一个非空的 b 或者抛出一个 b 为空的 NPE

val l = b !!.length

7.6 安全转换

普通的转换可能产生 ClassCastException 异常。另一个选择就是使用安全转换,如果不成功就返回空:

var b = "aaa"
val aInt: Int? = b as? Int
println(aInt)
输出如下:
I/System.out: null

这样如果 b 是 int 的类型的就输出,不是就返回 null
而不会像以前一样程序 crash 后报 ClassCastException 异常

8. 使用值检查并自动转换

使用 is 操作符检查一个表达式是否是某个类型的实例。如果对不可变的局部变量或属性进行过了类型检查,就没有必要明确转换:

fun printLength(obj: Any) {
    println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
}
fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // obj 将会在这个分支中自动转换为 String 类型
    return obj.length
  }

  // obj 在种类检查外仍然是 Any 类型
  return null
}

通过调用:

printLength("Incomprehensibilities")
printLength(1000)
printLength(listOf(Any()))
输出如下:
I/System.out: 'Incomprehensibilities' string length is 21 
I/System.out: '1000' string length is ... err, not a string 
I/System.out: '[java.lang.Object@72fd5e4]' string length is ... err, not a string 

当然我们也可以换一种方式来写

fun getStringLength(obj: Any): Int? {
  if (obj !is String) return null

  // obj 将会在这个分支中自动转换为 String 类型
  return obj.length
}

甚至可以这样

fun getStringLength(obj: Any): Int? {
    // obj 将会在&&右边自动转换为 String 类型
  if (obj is String && obj.length > 0) {
    return obj.length
  }

  return null
}

以上代码的输出结果是不变的。

9. 使用循环

val items = listOf("Google", "Apple", "Amazon")
for (index in items.indices) {
    println("item at $index is ${items[index]}")
}
// 输出如下: 
I/System.out: item at 0 is Google
I/System.out: item at 1 is Apple
I/System.out: item at 2 is Amazon

10. 使用 while 循环

val items = listOf("Google", "Apple", "Amazon")
var index = 0
while (index < items.size) {
    println("item at $index is ${items[index]}")
    index++
}

输出结果和 for 循环一样

11. 使用 when 表达式

Kotlin 中的 when 表达式就是类似于 Java 中的 switch 语句

when (obj) {
  1          -> "One"
  "Hello"    -> "Greeting"
  is Long    -> "Long"
  !is String -> "Not a string"
  else       -> "Unknown"
}
println(describe(1))
println(describe("Hello"))
println(describe(1000L))
println(describe(2))
println(describe("other"))

参数分别使用了『1』,『Hello』,『1000L』,『2』,『other』
分别对应下列的输出。和 switch 语法一模一样,只不过把一些过程给简化了。

// 输出如下:
I/System.out: item at 2 is kiwi
I/System.out: One
I/System.out: Greeting
I/System.out: Long
I/System.out: Not a string
I/System.out: Unknown

可能对于第四个有疑惑

println(describe(2))

!is String -> "Not a string"

以上意思是说 2 不是 String 类型的实例,结果为 true 所以输出了 『Not a string』

12. 使用ranges

使用 in 操作符检查数值是否在某个范围内:

val x = 10
val y = 9
if (x in 1..y+1) {
    println("fits in range")
}
// 输出如下:
I/System.out: fits in range

表达式的意思是说 x 是否在 1 ~ y + 1 的范围内
从定义的 x 和 y 的值来说,显而易见为 true

检查数值是否在范围外:

val list = listOf("a", "b", "c")

if (-1 !in 0..list.lastIndex) {
    println("list.lastIndex: ${list.lastIndex}")
    println("-1 is out of range")
}

if (list.size !in list.indices) {
    println("list.indices: ${list.indices}")
    println("list size is out of valid list indices range too")
}
// 输出如下:
I/System.out: list.lastIndex: 2
I/System.out: -1 is out of range
I/System.out: list.indices: 0..2
I/System.out: list size is out of valid list indices range too

!in 即不属于该范围 -1 不属于02,3也不属于02
所以他们的println语句都输出了。

在范围内迭代或者使用步进:

for (x in 1..5) {
  println(x)
}

println("----------------")

for (x in 1..10 step 2) {
  println(x)
}

println("----------------")

for (x in 9 downTo 0 step 3) {
  println(x)
}
// 输出如下:
I/System.out: 1
I/System.out: 2
I/System.out: 3
I/System.out: 4
I/System.out: 5
I/System.out: ----------------
I/System.out: 1
I/System.out: 3
I/System.out: 5
I/System.out: 7
I/System.out: 9
I/System.out: ----------------
I/System.out: 9
I/System.out: 6
I/System.out: 3
I/System.out: 0

step 跳跃
downTo 从大到小
看了 Log 日志,聪明的你应该懂了吧~~

13. 使用集合

对一个集合进行迭代:

val items = listOf("Google", "Apple", "Amazon")
for (item in items) {
    println(item)
}

println("----------------")

when {
       "tutu_oo" in items -> println("Change The World")
       "Google" in items -> println("My Dream")
}        

println("----------------")

val fruits = listOf("banana", "avocado", "apple", "kiwi")
   fruits
           .filter { it.startsWith("a") }
           .sortedBy { it }
           .map { it.toUpperCase() }
           .forEach { println(it) }
I/System.out: Google
I/System.out: Apple
I/System.out: Amazon
I/System.out: ----------------
I/System.out: My Dream
I/System.out: ----------------
I/System.out: APPLE
I/System.out: AVOCADO
I/System.out: ----------------

第一个是最普通的循环打印
接下来是 when 表达式,它只会执行一次
如果表达式是这样的

when {
       "Amazon" in items -> println("Change The World")
       "Google" in items -> println("My Dream")
} 
I/System.out: Google
I/System.out: Apple
I/System.out: Amazon
I/System.out: ----------------
I/System.out: Change The World
I/System.out: ----------------
I/System.out: APPLE
I/System.out: AVOCADO
I/System.out: ----------------

后面的 Google 即使也在 items 集合里面但是也不会输出『My Dream』

最后就是链式调用了,让我想到了 RxJava ,首先通过 filter 过滤只留下『a』 开头的,然后应该是自然排序,接着通过 map 转换成大写,最后将每一个都输出。

关于我

一只成长中的图图。

感谢

参考自:
https://www.kotlincn.net/docs/tutorials/android-plugin.html

https://huanglizhuo.gitbooks.io/kotlin-in-chinese/content/GettingStarted/Basic-Syntax.html

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

推荐阅读更多精彩内容