- 1.1 程序的逻辑控制
- if条件语句
- when条件语句
- while循环
- for-in循环
- 1.2 面向对象编程
- 继承
- 类的主构造函数
- 接口
- 数据类与单例类
- 1.3 Lambda编程
- 集合的创建与遍历
- 可变集合
- Set集合和List集合的区别
- 创建Map集合
- 集合的函数式API
- Java函数式API的使用
- 1.4 空指针检查
- 1.5 kotlin中的小魔术
- 函数的参数默认值
- 通过键值对的方式来传参
Kotlin中的if语句相比于Java有一个额外的功能,它是可以有返回值的,返回值就是if语句每一个条件中最后一行代码的返回值
// 简化前
fun largerNumber(num1: Int, num2: Int): Int {
var value = 0
if (num1 > num2) {
value = num1
} else {
value = num2
}
return value
}
// 简化后
fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
1.1.2 when条件语句
when语句和if语句一样,也是可以有返回值的
精确匹配
fun getScore(name: String) = when (name) {
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0
}
类型匹配
以下代码中,is关键字就是类型匹配的核心,它相当于Java中的instanceof关键字。Number类型的参数,这是Kotlin内置的一个抽象类,像Int、Long、Float、Double等与数字相关的类都是它的子类,所以这里就可以使用类型匹配来判断传入的参数到底属于什么类型。
fun checkNumber(num: Number) {
when (num) {
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
}
不带参数的用法
这种用法是将判断的表达式完整地写在when的结构体当中
fun getScore(name: String) = when {
name.startsWith("Tom") -> 86
name == "Jim" -> 77
name == "Jack" -> 95
name == "Lily" -> 100
else -> 0
}
1.1.3 while循环
while循环不管是在语法还是使用技巧上都和Java中的while循环没有任何区别
fun main(args: Array1.1.4 for-in循环){ var i = 1 while (i<=5){ println(i) i++ } }
val range = 0..10
上述代码表示创建了一个0到10的区间,并且两端都是闭区间。[0,10]
for (i in 0..10) {
println(i)
}
通过for-in循环来遍历这个区间
val range = 0 until 10
用until关键字来创建一个左闭右开的区间。[0,10)
for (i in 0 until 10 step 2) {
println(i)
}
for-in循环每次执行循环时会在区间范围内递增1,相当于Java for-i循环中i++的效果,而如果你想跳过其中的一些元素,可以使用step关键字
for (i in 10 downTo 1 step 2) {
println(i)
}
1.1.5 Kotlin中判断字符串或对象是否相等…和until关键字都要求区间的左端必须小于等于区间的右端,也就是这两种关键字创建的都是一个升序的区间。如果你想创建一个降序的区间,可以使用downTo关键字。[10,1]
1.2 面向对象编程 1.2.1 继承可以直接使用==关键字,而不用像Java那样调用equals()方法。
open关键字表示类被允许继承
open class Person{
}
在Java中继承的关键字是extends,而在Kotlin中变成了一个冒号
class Student: Person() {
}
1.2.2 类的主构造函数
主构造函数
主构造函数将会是你最常用的构造函数,每个类默认都会有一个不带参数的主构造函数,当然你也可以显式地给它指明参数。主构造函数的特点是没有函数体,直接定义在类名的后面即可。由于构造函数中的参数是在创建实例的时候传入的,不像之前的写法那样还得重新赋值,因此我们可以将参数全部声明成val。
class Student(val sno: String, val grade: Int) : Person() {
}
init结构体
主构造函数没有函数体,如果我想在主构造函数中编写一些逻辑,该怎么办呢?Kotlin给我们提供了一个init结构体,所有主构造函数中的逻辑都可以写在里面
class Student(val sno: String, val grade: Int) : Person() {
init {
println("sno is " + sno)
println("grade is " + grade)
}
}
继承时主构造参数如何传
我们在Student类的主构造函数中增加name和age这两个字段时,不能再将它们声明成val,因为在主构造函数中声明成val或者var的参数将自动成为该类的字段,这就会导致和父类中同名的name和age字段造成冲突。因此,这里的name和age参数前面我们不用加任何关键字,让它的作用域仅限定在主构造函数当中即可。
class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) {
...
}
次构造函数
使用关键字constructor声明;kotlin规定,当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
open class B(val name: String, val age: Int) {}
class A(val sno: String, val grade: Int, name: String, age: Int) : B(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
}
类中只有次构造函数,没有主构造函数
class Student : Person {
constructor(name: String, age: Int) : super(name, age) {
}
}
1.2.3 接口
interface Study {
fun readBooks()
fun doHomework()
}
open class Person(val name: String, val age: Int) {
}
class Student(name: String, age: Int) : Person(name, age), Study {
override fun readBooks() {
println("$name is reading.")
}
override fun doHomework() {
println("$name is doing homework.")
}
}
kotin允许对接口中定义的函数进行默认实现
interface Study {
fun readBooks()
fun doHomework() {
println("do homework default implementation.")
}
}
Java和Kotlin函数可见性修饰符对照表
| 修饰符 | Java | Kotlin |
|---|---|---|
| public | 所有类可见 | 所有类可见(默认) |
| private | 当前类可见 | 当前类可见 |
| protected | 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 |
| default | 同一包路径下的类可见(默认) | 无 |
| internal | 无 | 同一模块中的类可见 |
数据类
当在一个类前面声明了data关键字时,就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量
data class Cellphone(val brand: String, val price: Double)
单例类
在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可。
object Singleton {
fun singletonTest() {
println("singletonTest is called.")
}
}
1.3 Lambda编程
1.3.1 集合的创建与遍历
// 类似java写法 val list = ArrayList1.3.2 可变集合() list.add("Apple") list.add("Banana") // kotlin写法 val list1 = listOf("Apple", "Banana") // 使用for in 循环打印 for (str in list1) print(str)
使用listOf创建的是不可变集合,使用mutableListOf创建的才是可变集合
val list1 = mutableListOf("Apple", "Banana")
list1.add("Orange")
for (str in list1) print(str)
1.3.3 Set集合和List集合的区别
Set集合中是不可以存放重复元素的,如果存放了多个相同的元素,只会保留其中一份,这是和List集合最大的不同之处。
// 不可变 var set = setOf1.3.4 创建map集合("1","1","2") for (str in set) print(str) // 可变 val set1 = mutableSetOf("1","2") set1.add("3") for (str in set1) print(str)
// 创建可变map集合
val map = mutableMapOf("Apple" to 1, "Banana" to 2)
map["Orange"] = 3
// for in 循环打印map集合
for ((name, number) in map) print("$name is $number")
1.3.5 集合的函数式API
Lambda表达式的语法结构
{参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}
首先最外层是一对大括号,如果有参数传入到
Lambda表达式中的话,我们还需要声明参数列表,参数列表的结尾使用一个->符号,表示参
数列表的结束以及函数体的开始,函数体中可以编写任意行代码(虽然不建议编写太长的代
码),并且最后一行代码会自动作为Lambda表达式的返回值。
Lambda的定义,如果用最直白的语言来阐述的话,Lambda就是一小段可以作为参数传递的代码。
常用的函数式API—maxBy函数
maxBy函数的工作原理是根据我们传入的条件来遍历集合,从而找到该条件下的最大值
val list = listOf("Apple", "Banana")
// 简化前
val lambda = { result: String -> result.length }
val maxLength = list.maxByOrNull(lambda)
// 简化后
val maxLength = list.maxByOrNull { it.length }
常用的函数式API—filter函数,map函数
map函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成一个另外的值,映射的规则在Lambda表达式中指定,最终生成一个新的集合。
filter函数是用来过滤集合中的数据的,它可以单独使用,也可以配合刚才的map函数一起使用。
val list = listOf("Apple", "Banana")
val newList = list.filter { it.length > 2 }.map { it.length }
for (str in newList) print(str)
常用的函数式API—any和all函数
其中any函数用于判断集合中是否至少存在一个元素满足指定条件,all函数用于判断集合中是否所有元素都满足指定条件。
val list = listOf("Apple", "Banana")
val anyList = list.any { it.length > 2 }
val allList = list.all { it.length > 2 }
1.3.6 Java函数式API的使用
Kotlin中匿名类的写法
Kotlin中匿名类的写法和Java有一点区别,由于Kotlin完全舍弃了new关键字,因此创建匿名类实例的时候就不能再使用new了,而是改用了object关键字。这种写法虽然算不上复杂,但是相比于Java的匿名类写法,并没有什么简化之处.
Thread(object : Runnable {
override fun run() {
}
}).start()
Java函数式API的使用
Kotlin中调用Java方法时也可以使用函数式API,只不过这是有一定条件限制的。具体来讲,如果我们在Kotlin代码中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口参数,就可以使用函数式API。Java单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数式API。
Thread { print("thread") }.start()
1.4 空指针检查
Kotlin将空指针异常的检查提前到了编译时期,如果我们的程序存在空指针异常的风险,那么在编译的时候会直接报错,修正之后才能成功运行,这样就可以保证程序在运行时期不会出现空指针异常了。
可为空的类型系统 Int? String?
很简单,就是在类名的后面加上一个问号。比如,Int表
示不可为空的整型,而Int?就表示可为空的整型;String表示不可为空的字符串,而String?就表示可为空的字符串。
判空辅助工具 ?.操作符
首先学习最常用的?.操作符。这个操作符的作用非常好理解,就是当对象不为空时正常调用相应的方法,当对象为空时则什么都不做。
fun doStudy(study: Study?){
study?.readBooks()
study?.doHomework()
}
?:操作符
?:操作符。这个操作符的左右两边都接收一个表达式,
如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
val a = 0
val b = 0
var c = if (a != null) {
a
} else {
b
}
// 使用?:操作符简化代码
c = a ?: b
将?.和?:操作符结合到了一起使用
// 简化前
fun getTextLength1(text: String?): Int {
if (text != null) {
return text.length
}
return 0
}
// 使用?.和 ?:简化
fun getTextLength2(text: String?) = text?.length ?: 0
非空断言工具 !!
确信的对象不会为空,所以不用你来帮我做空指针检查了,强行通过编译,可以使用非空断言工具,写法是在对象的后面加上!!
var content: String? = "hello"
fun printUpperCase() {
val upperCase = content!!.toUpperCase()
println(upperCase)
}
辅助工具—let函数
obj.let { obj2 ->
// 编写具体的业务逻辑
}
fun printUpperCase() {
val content: String? = "hello"
val upperCase = content?.let {
it.toUpperCase()
it.length
}
println(upperCase)
}
1.5 kotlin中的小魔术
函数的参数默认值
定义函数的时候给任意参数设定一个默认值,这样当调用此函数时就不会强制要求调用方为此参数传值,在没有传值的情况下会自动使用参数的默认值。
fun printParams(num: Int, str: String = "hello") {
println("num is $num , str is $str")
}
通过键值对的方式来传参
printParams(str = "world", num = 123)
fun printParams(num: Int = 100, str: String) {
println("num is $num , str is $str")
}
fun main() {
printParams(str = "world")
}



