1. 初始Kotlin
1. Kotlin主要特征
-
目标平台
Kotlin的首要目标是提供一种更简洁、更高效、更安全的替代Java的语言,并且适用于现今为止使用的Java的所有环境。除了Java之外,Kotlin还可以编译成JavaScript。
Kotlin的最常用的应用场景:- 编写服务器端代码(典型的代表是Web应用后端)
- 创建Android设备的移动应用
-
静态类型
Kotlin和Java一样是一种静态类型的编程语言,意味着所有表达式的类型在编译期已经确定了。
静态类型的好处:- 性能--方法调用速度更快
- 可靠性--编译期验证了程序的正确性
- 可维护性--陌生代码更容易维护
- 工具支持--静态类型使IDE能提供可靠的重构、精确的代码补全以及其它特性
-
函数式和面向对象
函数式编程的核心:- 头等函数--把函数(一小段行为)当做值使用,可以用变量保存它,把它当作参数传递,或者当作其他函数的返回值。
- 不可变性--使用不可变对象,这保证了它们的状态在其创建之后不能再变化。
- 无副作用--使用的是纯函数。此类函数在输入相同时会产生同样的结果,并且不会修改其他对象的状态,也不会和外面的世界交互。
Kotlin允许你使用函数式编程风格但并没有强制你使用它,Kotlin拥有丰富的特性集包括:
- 函数类型, 允许函数接受其他函数作为参考,或者返回其他函数
- lambda表达式, 让你用最少的样板代码方便的传递代码块
- 数据类, 提供了创建不可变值对象的简明语法
- 标准库中包括丰富的API集合,让你用函数式编程风格操作对象和集合
2. Kotlin应用
- 服务器端的Kotlin
- Android端的Kotlin
3. Kotlin的设计哲学
- 务实
- 简洁,比Java的代码量更少
- 安全,最重要的一点处理了可空数据
- 互操作性,调用Java方法,继承类和实现接口,应用Java注解
2. Kotlin基础
1. 基本要素:函数和变量
1. 函数
- 先来写个main函数
fun main(args: Array<String>) {
println("Hello World") // 注释依然可以用 //或/**/,语句可以省略;
}
复制代码
- 几种函数的写法
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
>>> println(max(1, 2))
2
复制代码
fun max(a: Int, b: Int): Int = if (a > b) a else b
复制代码
fun max(a: Int, b: Int) = if (a > b) a else b
复制代码
if在Kotlin中是表达式,从以上代码很明显看出很简洁
2. 变量
var--可变,val--不可变(类似Java的final)
var age: Int = 25 //显式指明变量的类型
var name = "Kotlin" //可以隐藏变量的类型
var nickname: String //如果变量声明的时候没有初始化,就必须要指明类型
nickname = "渣渣灰"
复制代码
尽管val引用自身是不可变的,但是它指向的对象可能是可变的,官方建议先考虑用val,除非必须用var声明。例如:
val colors = arrayListOf("Red")
colors.add("White")
复制代码
2. 类和属性
1. 类
先看一个简单的演员Java类
public class Actor {
private String role;
public void setRole(String role) {
this.role = role;
}
public String getRole() {
return role;
}
}
复制代码
再来看Kotlin中的几种写法
class Actor1 { //class的定义默认为public,所以可以省略
var role: String? = null //属性可为空,可省略get,set
}
//或者下面这种
class Actor(var role: String?)
复制代码
如果这个类只起到JavaBean的作用,而无其它额外方法,用'data'来定义类
data Actor(var role: String?)
复制代码
关于类还有很多内容,比如内部类,密封类,伴随对象等等,后续的文章会提到
2. 属性
上面的类中已经有了一个属性叫角色,现在再给演员加几个属性,让我们更多的对属性做个了解
class Actor {
var role: String? = null
val name: String? = null //val修饰的不能set,只能被赋值一次
get() {
return if (isOverseas) nameEnglish else nameChinese
}
var nameEnglish: String? = null
set(value: String?) { //这里的默认set get可以省略
field = value
}
get
var nameChinese: String? = null
var isOverseas: Boolean = false
}
fun main(args: Array<String>) {
val goodActor = Actor()
goodActor.nameEnglish = "Louis Koo Tin-lok"
goodActor.nameChinese = "古天乐"
//来大陆做拍广告来了,暂没出国
goodActor.isOverseas = false
goodActor.role = "贪玩蓝月游戏代言人"
println(goodActor.name) //输出 >>> 古天乐
}
复制代码
3. 枚举和“when”
1. 枚举
枚举依然很简单
enum class Color {
RED, ORANGE, YELLOW
}
enum class Color(val r: Int, val g: Int, val b: Int) {
//在每个常量创建的时候指定属性值
RED(255, 0, 0), GREEN(0, 255, 0), BLUE(0, 0, 255);
//给枚举类定义一个方法
fun rgb() = (r.shl(8) + g).shl(8) + b //shl是位运算符,左移
}
>>> println(Color.BLUE.rgb())
255
复制代码
2. when表达式
先看个简单的when使用
fun getTranslate(color: Color) =
when (color) {
Color.RED, Color.BLUE -> "我喜欢的颜色"
Color.GREEN -> {
println("我不喜欢的颜色")
"绿"
}
}
复制代码
这个简单的用法是不是一下子就惊呆了,似Java中的Switch,却强大了很多,再来看看不带参数的when
fun mixColor(color1: Color, color2: Color) =
when {
(color1 == Color.RED && color2 == Color.GREEN) -> "黄"
(color1 == Color.YELLOW && color2 == Color.BLUE) -> "绿"
else -> "不知道啥色"
}
复制代码
4. 迭代:"while"循环和"for"循环
1. while循环
while几乎和Java的while一致
2. for循环
先看用区间(关于区间的知识点,后边再说)遍历数字,字符
for(i in 1..9) {
println(i) //依次输出123456789
}
for(c in 'A'..'F') {
println(c)
}
// 左闭右开区间,合法值包括11,但不包括66
for (i in 11 until 66) { ... }
// 每次默认递增1,这里改为每次递增4
for (i in 23..89 step 4) { ... }
// for循环默认递增,这里使用downTo表示递减
for (i in 50 downTo 7) { ... }
// 遍历集合
for ((index, value) in array.withIndex()) {
println("the element at $index is $value")
}
// 遍历map
for((key,value) : map) {
// $为取值操作符,这和 println(key + "--->" + value)效率一样,但更简洁
println("$key--->${value.toString()}")
}
// 用不到的参数可以用_代替
for((key,_) : map) {
println("key: $key")
}
复制代码
5. 异常处理
先看个中规中矩的处理方式
fun readNumber(reader: BufferedReader): Int? {
try {
val line = reader.readLine()
return Integer.parseInt(line)
} catch (e: NumberFormatException) {
return null
} finally {
reader.close()
}
}
复制代码
try作为表达式
fun readNumber(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine())
} catch (e: NumberFormatException) {
return
}
}
复制代码
此外,如果方法中显式用throw抛出异常,不用像Java那样在方法名的后面声明抛异常