以下内容摘自郭霖《第一行代码》第三版
… 左闭右闭
until 左闭右开
downTo 倒序左闭右闭
step 代表每次递增的数字
ps:主要用于for循环和while循环等
Kotlin中条件语句用when关键词
fun getScore(name: String) = when(name){
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0 // 相当于switch-case语句里面的default
}
fun getScore2(name: String) = when{
name.startsWith("Tom") -> 86
name == "Jim" -> 77
name == "Jack" -> 95
name == "Lily" -> 100
else -> 0 // 相当于switch-case语句里面的default
}
fun checkNumber(num: Number){
when(num){
is Int -> println("number is Int")
is Double -> println("number is Double")
is Float -> println("number is Float")
else -> println("number is not support")
}
}
在Kotlin中任何一个非抽象类默认都是不可以被继承的
:用来表示继承关系,而且需要被继承的类在关键字class前面加上open
open class Person(){
var name = ""
var age = 0
}
class Student: Person(){
var sno = ""
var grade = 0
}
class Student: Person{
constructor(name: String, age: Int): super(name, age){
}
}
使用,来表示实现关系,并且不需要加括号
允许对接口中定义的函数进行默认实现
interface Study {
fun readBooks()
fun doHomework(){
println("do homework default implementation.")
}
}
Java中是private、protected、public和default(默认项)
Kotlin中是private(同Java)、protected(只对当前类和子类可见)、public(默认项,同Java)和internal(比如我们开发了一个模块给别人使用,但是有一些函数只允许在模块内部调用,不想暴露给外部,就可以将这些函数声明成internal)
修饰符 | Java | Kotlin |
---|---|---|
public | 所有类可见 | 所有类可见(默认) |
protected | 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 |
private | 当前类可见 | 当前类可见 |
default | 同一包路径下的类可见(默认) | 无 |
internal | 无 | 同一模块中的类可见 |
当在一个类前面声明了data关键字时,就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成。
直接将class关键字改为object关键字
object Singleton {
fun singletonTest(){
println("singletonTest is called.")
}
}
调用单例类中的函数比较类似于Java中静态方法的调用方式:
Singleton.singletonTest()
// listOf表示不可变的集合,即该集合只可读
val list = listOf("apple", "banana", "orange", "pear", "Grape")
for(fruit in list){
println(fruit)
}
// 获取单词长度最大的那个
println("The max length of list is " + list.maxBy { it.length })
// mutableListOf表示可变的集合
val list1 = mutableListOf("apple", "banana", "orange", "pear", "Grape")
list1.add("watermelon")
for(fruit in list1){
println(fruit)
}
val set = setOf("apple", "banana", "orange", "pear", "Grape", "banana")
for(fruit in set){
println(fruit)
}
val set1 = mutableSetOf("apple", "banana", "orange", "pear", "Grape", "banana")
set1.add("watermelon")
set1.add("orange")
for(fruit in set1){
println(fruit)
}
val map = HashMap<String, Int>()
map.put("Apple", 1)
map.put("banana", 2)
map.put("orange", 3)
map.put("pear", 4)
map.put("grape", 5)
val number = map.get("Apple")
// 不建议使用上述get()和put()方法,建议使用以下方法
map["Apple"] = 1
map["banana"] = 2
map["orange"] = 3
map["pear"] = 4
map["grape"] = 5
val number = map["Apple"]
// 但是还有更简单的方法
val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
// 遍历
for((fruit, number) in map){
println("fruit is " + fruit + ", number is " + number)
}
语法结构:
{参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}
首先最外层是一对大括号,如果有参数传入到Lambda表达式中的话,我们还需要声明参数列表,参数列表的结尾使用一个->符号,表示参数列表的结束以及函数体的开始,函数体中可以编写任意行代码(虽然不建议编写太长的代码),并且最后一行代码会自动作为Lambda表达式的返回值。
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
val lambda = {fruit: String -> fruit.length}
val maxLengthFruit = list.maxBy(lambda)
println("The max length of list is " + maxLengthFruit)
// 进行简化
val maxLengthFruit = list.maxBy({fruit: String -> fruit.length})
// Kotlin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面
val maxLengthFruit = list.maxBy(){fruit: String -> fruit.length}
// 如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略
val maxLengthFruit = list.maxBy{fruit: String -> fruit.length}
// 由于Kotlin拥有出色的类型推导机制,Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型
val maxLengthFruit = list.maxBy{fruit -> fruit.length}
// 当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替
val maxLengthFruit = list.maxBy { it.length }
filter函数是用来过滤集合中的数据的,它可以单独使用,也可以配合刚才的map函数一起使用。
fun main() {
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val newList = list.filter { it.length <= 5 }.map { it.toUpperCase() }
for (fruit in newList) {
println(fruit)
}
}
any函数用于判断集合中是否至少存在一个元素满足指定条件,all函数用于判断集合中是否所有元素都满足指定条件。
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
var anyResult = list.any { it.length <= 5 }
var allResult = list.all { it.length <= 5 }
// anyResult = true, allResult = false
println("anyResult = " + anyResult + ", allResult = " + allResult)
Thread(object: Runnable{
override fun run() {
println("Thread is running...")
}
}).start()
// 对代码进行精简
Thread(Runnable {
println("Thread is running...")
}).start()
// 再精简
Thread({
println("Thread is running...")
}).start()
// 继续精简
Thread{
println("Thread is running...")
}.start()
Kotlin默认所有的参数和变量都不可为空,Kotlin将空指针异常的检查提前到了编译时期
可为空的类型:在类名的后面加上一个问号。Int表示不可为空的整型,而Int?就表示可为空的整型;String表示不可为空的字符串,而String?就表示可为空的字符串
?.操作符。当对象不为空时正常调用相应的方法,当对象为空时则什么都不做。
if (a != null) {
a.doSomething()
}
// 直接替换为
a?.doSomething()
?:操作符。这个操作符的左右两边都接收一个表达式,如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
var a: Int = 10
var b: Int = 20
val c = if(a != null){
a
}else{
b
}
// 直接替换为
val c1 = a ?: b
想要强行通过编译,使用非空断言,在对象后面加上!!。这是一种有风险的写法意在告诉Kotlin,我非常确信这里的对象不会为空,所以不用你来帮我做空指针检查了,如果出现问题,你可以直接抛出空指针异常,后果由我自己承担。(有风险)
var content: String? = "hello"
fun main() {
if (content != null) {
printUpperCase()
}
}
fun printUpperCase() {
val upperCase = content.toUpperCase()
println(upperCase)
}
这个代码是无法通过编译的,需要改成以下代码:
fun printUpperCase() {
val upperCase = content!!.toUpperCase()
println(upperCase)
}
// 本来我们进行一次if判断就能随意调用study对象的任何方法,但受制于?.操作符的限制,现在变成了每次调用study对象的方法时都要进行一次if判断
fun doStudy(study: Study?){
if(study != null){
study.doHomework()
}
if(study != null){
study.readBooks()
}
}
// 结合使用?.操作符和let函数来对代码进行优化
fun doStudy1(study: Study?){
study?.let { stu ->
stu.doHomework()
stu.readBooks()
}
}
// 当Lambda表达式的参数列表中只有一个参数时,可以不用声明参数名,直接使用it关键字来代替即可
fun doStudy3(study: Study?){
study?.let {
it.doHomework()
it.readBooks()
}
}
let函数是可以处理全局变量的判空问题的,而if判断语句则无法做到这一点
val name = "Annie"
val str = "hello, $name. Nice to meet you!"
可以通过键值对的方式来传参,从而不必像传统写法那样按照参数定义的顺序来传参
fun printParams(num: Int = 100, str: String) {
println("num is $num , str is $str")
}
fun main() {
printParams(str = "world")
}
当次构造函数的作用是提供使用更少参数来对类进行实例化的方式时,我们完全可以通过只编写一个主构造函数,然后给参数设定默认值的方式来实现。