上一篇讲了Kotlin的介绍和基本数据类型,这一篇讲讲程序的结构。
函数(function)
单函数表达式
//当函数只返回单个表达式时,大括号可以省略并在 = 后面定义函数体
fun double(x: Int): Int = x*2
//在编译器可以推断出返回值类型的时候,返回值的类型可以省略:
fun double(x: Int) = x * 2
拓展方法
中缀符号
它们是成员函数或者是扩展函数 只有一个参数 使用infix
关键词进行标记
//给 Int 定义一个扩展方法
infix fun Int.shl(x: Int): Int {
...
}
1 shl 2 //用中缀注解调用扩展函数
1.shl(2)
函数范围
Kotlin 中可以在文件顶级声明函数,这就意味者你不用像在Java,C#或是Scala一样创建一个类来持有函数。除了顶级函数,Kotlin 函数可以声明为局部的,作为成员函数或扩展函数。详细的请看文档
泛型函数
//函数可以有泛型参数,样式是在函数后跟上尖括号。
fun sigletonArray<T>(item: T): Array<T> {
return Array<T>(1, {item})
}
内联函数 高阶函数 尾递归函数在文档中会详细介绍,我后面的文章也会介绍。
表达式
if表达式
在kotlin中一切都是表达式,也就是说一切都有返回值。我们可以像Java,C等等语言正常使用它。
if(value > 0){
println("这个数字大于0")
}else if(value <= 0){
println("这个数组小于等于0")
}
我们也可以把结果赋给一个变量
val str = if(value != null && value.length > 0)value else null
when表达式
when表达式像是Java中的switch/case,但是你会发现when表达式要牛X的多,因为我觉得他是增强版的switch,他能干很多switch做不到的工作。switch往往受类型的限制和表达式的限制,而且写起来复杂,如我们不得不在一个case需要停止的时候添加break,分支多的时候也需要写很多个break。when表达式解决了这些问题。
var value = when(x){
1 -> println(x)
2 -> println(X)
"打豆豆" -> println(x)
in 60..100 -> println("恭喜你骚年,及格了")
is String -> println("嗯 这玩意是个字符串")
else println("这啥啊 我一脸蒙圈")
}
For循环
for(item in collection){
println(item)
}
for(index in 0..list.size() -1){
println(index)
}
还有想要反向循环for(index in 10..0)这样是不会循环的 Range默认只会增长 所以这么写
for(i in 10 downTo 0){
println(i)
}
我们也可以定义一个值的增长的间隙
for(i in 1..10 step 2){
println(i)
}
for(i in 10downTo 1 step 2){
println(i)
}
返回与跳转(直接复制中文文档了)
Kotlin 有三种机构跳转操作符
return break 结束最近的闭合循环 continue 跳到最近的闭合循环的下一次循环
break 和 continue 标签
在 Kotlin 中表达式可以添加标签。标签通过 @ 结尾来表示,比如:abc@
,fooBar@
都是有效的(参看语法)。使用标签语法只需像这样:
loop@ for (i in 1..100){
//...
}
现在我们可以用标签实现 break 或者 continue 的快速跳转:
loop@ for (i in 1..100) {
for (j in i..100) {
if (...)
break@loop
}
}
break 是跳转标签后面的表达式,continue 是跳转到循环的下一次迭代。返回到标签处在字面函数,局部函数,以及对象表达式中,函数可以在 Kotlin 中被包裹。return 允许我们返回到外层函数。最重要的例子就是从字面函数中返回,还记得我们之前的写法吗:
fun foo() {
ints.forEach {
if (it == 0) return
print(it)
}
}
return 表达式返回到最近的闭合函数,比如 foo
(注意这样非局部返回仅仅可以在内联函数中使用)。如果我们需要从一个字面函数返回可以使用标签修饰 return :
fun foo() {
ints.forEach lit@ {
if (it ==0) return@lit
print(it)
}
}
现在它仅仅从字面函数中返回。经常用一种更方便的含蓄的标签:比如用和传入的 lambda 表达式名字相同的标签。
fun foo() {
ints.forEach {
if (it == 0) return@forEach
print(it)
}
}
另外,我们可以用函数表达式替代字面函数。在函数表达式中使用 return 语句可以从函数表达式中返回。
fun foo() {
ints.forEach(fun(value: Int){
if (value == 0) return
print(value)
})
}
当返回一个值时,解析器给了一个参考,比如(原文When returning a value, the parser gives preference to the qualified return, i.e.):
return@a 1
命名函数自动定义标签:
foo outer() {
foo inner() {
return@outer
}
}
包
这个东西真心没啥 看看文档吧
位运算
基本运算符
运算符与Java等语言近乎相同,值得一提的是运算符的重载。
运算符重载
这里请务必看文档里面的重载运算符对照表,这里实在是没必要在粘贴一遍
拓展函数的操作符
我们不需要拓展我们自己的类,但我们去使用拓展函数去拓展我们已存在的类让第三方的类存在更多的操作。
举个例子,我们可以向访问List的方式去访问ViewGroup的view:
operator fun ViewGroup.get(position:Int):View = getChildAt(position)
异常
跟java使用方式一样,但是有Kotlin独有的特性就是可以当做一个表达式,有返回值
异常类
所有的异常类都是 Exception
的子类。每个异常都有一个消息,栈踪迹和可选的原因。
使用 throw 表达式,抛出异常
throw MyException("Hi There!")
使用 try 捕获异常
try {
// some code
}
catch (e: SomeException) {
// handler
}
finally {
// optional finally block
}
有可能有不止一个的 catch 块。finally 块可以省略。
try 是一个表达式
try 可以有返回值:
val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }
try 返回值要么是 try 块的最后一个表达式,要么是 catch 块的最后一个表达式。finally 块的内容不会对表达式有任何影响。
检查异常
Kotlin 中没有异常检查。这是由多种原因造成的,我们这里举个简单的例子
下面是 JDK StringBuilder
类实现的一个接口
Appendable append(CharSequence csq) throws IOException;
这个签名说了什么? 它说每次我把 string 添加到什么东西(StringBuilder 或者 log console 等等)上时都会捕获 IOExceptions
为什么呢?因为可能涉及到 IO 操作(Writer 也实现了 Appendable)... 所以导致所有实现 Appendable 的接口都得捕获异常
try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}
这样是不利的,参看Effective java
Bruce Eckel 在java 需要异常检查吗?说到:
Examination of small programs leads to the conclusion that requiring exception specifications could both enhance developer productivity and enhance code quality, but experience with large software projects suggests a different result – decreased productivity and little or no increase in code quality.
注解 反射
请看文档吧 写的很详细
后记:
首先感谢Kotlin官方文档和Kotlin-for-Android-developers和贡献Kotlin学习资料的博客大神们。
我尽量全面的概括知识点,主要是为学习过后作总结和复习,若有遗漏,请告诉我,还请谅解。