完整代码Gitee地址:kotlin-demo: 15天Kotlin学习计划
第一天学习内容代码:Chapter1类
目录
创建一个LearnKotlin.kt类
知识点1:日志输出
fun main() {
//1、日志打印
println("日志输出")
}
点run执行结果
知识点2:变量声明 val、var
fun main() {
//2、val声明一个不可变变量 对应java的final
//var声明一个可变变量 好的代码习惯,优先使用val
val a = 10
val b = 37
}
知识点3:定义函数、语法糖
fun main() {
//3、定义函数
val a = 10
val b = 37
println("methodName = " + methodName(a, b))
//函数的语法糖写法
fun methodName(param1: Int, param2: Int) = max(param1, param2)
println("methodName = " + methodName(a, 20))
}
//fun(function的简写)是定义函数的关键字
//fun后面的是函数名
//函数名后面紧跟着一对括号,里面可以声明该函数接收什么参数,参数的数量可以是任意多个
//参数括号后面的那部分是可选的,用于声明该函数会返回什么类型的数据
fun methodName(param1: Int, param2: Int): Int {
//返回两个参数中更大的那个数
return max(param1, param2)
}
打印日志结果为:
知识点4:条件语句 if、where
Kotlin中的条件语句主要有两种实现方式:if和when。
如果你熟悉Java的话,应该知道Java中的switch语句并不怎么好用。首先,switch只能传入整型或短于整型的变量作为条件,JDK 1.7之后增加了对字符串变量的支持,但如果你的判断逻辑使用的并非是上述几种类型的变量,那么不好意思,switch并不适合你。其次,switch中的每个case条件都要在最后主动加上一个break,否则执行完当前case之后会依次执行下面的case,这一特性曾经导致过无数奇怪的bug,就是因为有人忘记添加break。
而Kotlin中的when语句不仅解决了上述痛点,还增加了许多更为强大的新特性,有时候它比if语句还要简单好用,现在我们就来学习一下吧
fun main() {
//4、条件语句 if、where
conditional()
}
//4、条件语句
fun conditional() {
//用if判断二个函数的较大值
println("ifMethodName = " + ifMethodName(20, 50))
//语法糖写法
fun ifMethodName1(num1: Int, num2: Int) =
if (num1 > num2) {
num1
} else {
num2
}
//语法糖再精简
fun ifMethodName(num1: Int, num2: Int) = if (num1 > num2) num1 else num2 * 2
println("ifMethodName = " + ifMethodName(15, 35))
//用where判断成绩,与Java相比不用写break,且是有返回值的可精简为
fun whenStudent(name: String) =
when (name) {
"Peace" -> 60
"Jay" -> 72
"what" -> 80
else -> 0
}
println("ifStudent = " + whenStudent("Jay"))
//用where判断参数类型
fun whenType(num: Number) =
when (num) {
is Int -> println("is Int")
is Double -> println("is Double")
is Long -> println("is Long")
is Float -> println("is Float")
is Short -> println("is Short")
else -> println("else")
}
whenType(1234567890987654321)
//如果我们不在when语句中传入参数的话,还可以这么写
//举个例子,假设所有名字以Pea开头的人,他的分数都是90分,这种场景如果用带参数的when语句来写就无法实现
fun whenStu(name: String) = when {
name.startsWith("Pea") -> 90
name == "Peace" -> 60
name == "Jay" -> 72
name == "what" -> 80
else -> 0
}
println("whenStu = " + whenStu("Peace"))
}
//用if判断二个函数的较大值
fun ifMethodName(num1: Int, num2: Int): Int {
// var value = 0
// if (num1 > num2) {
// value = num1
// } else{
// value = num2
// }
//if是有返回值的,可以简化为
return if (num1 > num2) {
num1
} else {
num2
}
}
打印日志结果为:
知识点5:循环语句 for 、代码区间
Kotlin在for循环方面做了很大幅度的修改,Java中最常用的for-i循环在Kotlin中直接被舍弃了,而Java中另一种for-each循环则被Kotlin进行了大幅度的加强,变成了for-in循环,所以我们只需要学习for-in循环的用法就可以了
val value = 0..10,这种语法结构看上去挺奇怪的吧?但在Kotlin中,它是完全合法的。上述代码表示创建了一个0到10的区间,并且两端都是闭区间,这意味着0到10这两个端点都是包含在区间中的,用数学的方式表达出来就是[0, 10]。
Kotlin中可以使用until关键字来创建一个左闭右开的区间,使用step跳过区间内的元素,使用downTo遍历降序区间。
fun main() {
//5、循环语句 for
loopInfo()
}
//5、循环语句 for
fun loopInfo() {
//使用for-in遍历区间
val value = 0..10
for (i in value) {
print(" $i")
}
//双端闭区间不如单端闭区间好用,相信你一定知道数组的下标都是从0开始的,
//一个长度为10的数组,它的下标区间范围是0到9,因此左闭右开的区间在程序设计当中更加常用。
//Kotlin中可以使用until关键字来创建一个左闭右开的区间
//使用until替代..关键字,就不会打印10
println(" ")
val range = 0 until 10
for (i in range) {
print(" $i")
}
//如果想跳过其中的一些元素,可以使用step关键字
//上述代码表示在遍历[0, 10)这个区间的时候,每次执行循环都会在区间范围内递增2,
//相当于for-i循环中i = i + 2的效果
println(" ")
for (i in range step 2){
print(" $i")
}
//前面的..和until关键字都要求区间的左端必须小于等于区间的右端,
//也就是这两种关键字创建的都是一个升序的区间。
//如果你想创建一个降序的区间,可以使用downTo关键字
println(" ")
for (i in 10 downTo 0){
print(" $i")
}
println(" ")
}
打印日志结果为:
知识点6:面向对象
不同于面向过程的语言(比如C语言),面向对象的语言是可以创建类的。类就是对事物的一种封装,比如说人、汽车、房屋、书等任何事物,我们都可以将它封装一个类,类名通常是名词。而类中又可以拥有自己的字段和函数,字段表示该类所拥有的属性,比如说人可以有姓名和年龄,汽车可以有品牌和价格,这些就属于类中的字段,字段名通常也是名词。而函数则表示该类可以有哪些行为,比如说人可以吃饭和睡觉,汽车可以驾驶和保养等,函数名通常是动词。
fun main() {
//6、面向对象
objectView()
}
//6、面向对象
fun objectView() {
//拥有了3种方式来对StudentModel类进行实体化,
//分别是通过不带参数的构造函数、通过带两个参数的构造函数、通过带4个参数的构造函数
val student1 = StudentModel()
val student2 = StudentModel("周润发",28)
val student3 = StudentModel("111222",3,"周润发",28)
//类中只有次构造函数,没有主构造函数写法
val student = StudentModel1("333444",6,"刘德华",18)
}
创建StudentModel数据模型
/**
* Created by: PeaceJay
* Created date: 2021/10/25
* Description: 学生信息模型
*/
//继承了PersonModel的姓名与年龄
//sno学号 grade年级 name姓名 age年龄
class StudentModel(sno: String, grade: Int, name: String, age: Int) : PersonModel(name, age) {
//主构造函数没有函数体,如果我想在主构造函数中编写一些逻辑,该怎么办呢?
//Kotlin给我们提供了一个init结构体
init {
println("sno=$sno, grade=$grade,name=$name,age$age")
}
//次构造函数是通过constructor关键字来定义的,通过this关键字调用了主构造函数
//第一个次构造函数接收name和age参数,然后它又通过this关键字调用了主构造函数,并将sno和grade这两个参数赋值成初始值
constructor(name: String, age: Int) : this("", 0, name, age) {
}
//第二个次构造函数不接收任何参数,它通过this关键字调用了我们刚才定义的第一个次构造函数,
//并将name和age参数也赋值成初始值,由于第二个次构造函数间接调用了主构造函数,因此这仍然是合法的
constructor() : this("", 0) {
}
}
类中只有次构造函数,没有主构造函数写法
//首先Student类的后面没有显式地定义主构造函数,同时又因为定义了次构造函数,
//所以现在Student类是没有主构造函数的。那么既然没有主构造函数,
//继承Person类的时候也就不需要再加上括号了
class StudentModel1 : PersonModel {
constructor(sno: String, grade: Int,name: String, age: Int) : super(name, age) {
println("sno=$sno, grade=$grade,name=$name,age$age")
}
}
打印日志结果为:
知识点7:接口、函数修饰符
Kotlin中的接口部分和Java几乎是完全一致的。接口是用于实现多态编程的重要组成部分。我们都知道,Java是单继承结构的语言,任何一个类最多只能继承一个父类,但是却可以实现任意多个接口,Kotlin也是如此。
我们可以在接口中定义一系列的抽象行为,然后由具体的类去实现。下面还是通过具体的代码来学习一下,首先创建一个Study接口,并在其中定义几个学习行为。
/**
* Created by: PeaceJay
* Created date: 2021/10/25
* Description: 定义学生接口
*/
interface Study {
//在Study接口中添加几个学习相关的函数
fun readBooks()
fun doHomeWork()
//我们给doHomework()函数加上了函数体,并且在里面打印了一行日志。
//如果接口中的一个函数拥有了函数体,这个函数体中的内容就是它的默认实现。
//现在当一个类去实现Study接口时,只会强制要求实现readBooks()/doHomeWork()函数,
//而newDoHomeWork()函数则可以自由选择实现或者不实现,不实现时就会自动使用默认的实现逻辑
fun newDoHomeWork(){
println("newDoHomeWork")
}
}
接下来就可以让StudentBean类去实现Study接口了
//Java中继承使用的关键字是extends,实现接口使用的关键字是implements,
//而Kotlin中统一使用冒号,中间用逗号进行分隔
//必须加var否则无法引用
class StudentBean(var name: String, age: Int) : PersonModel(name, age), Study {
override fun readBooks() {
println("$name is readBooks")
}
override fun doHomeWork() {
println("$name is doHomeWork")
}
}
现在我们可以在main()函数中编写如下代码来调用这两个接口中的函数
fun main() {
//7、接口
interfaceView()
}
//7、接口
//接口是用于实现多态编程的重要组成部分。我们都知道,Java是单继承结构的语言,
//任何一个类最多只能继承一个父类,但是却可以实现任意多个接口,Kotlin也是如此
fun interfaceView() {
val student = StudentBean("刘德华",18)
doStudy(student)
}
//演示一下多态编程的特性
fun doStudy(student: StudentBean) {
student.readBooks()
student.doHomeWork()
student.newDoHomeWork()
}
打印日志结果为:
了解函数的可见性修饰符
Java中有public、private、protected和default(什么都不写)这4种函数可见性修饰符
Kotlin中也有4种,分别是public、private、protected和internal;
private:private修饰符在两种语言中的作用是一模一样的,都表示只对当前类内部可见
public:public修饰符的作用虽然也是一致的,表示对所有类都可见,但是在Kotlin中public修饰符是默认项,而在Java中default才是默认项;
protected:protected关键字在Java中表示对当前类、子类和同一包路径下的类可见,在Kotlin中则表示只对当前类和子类可见;
default:Kotlin抛弃了Java中的default可见性(同一包路径下的类可见),引入了一种新的可见性概念,只对同一模块中的类可见,使用的是internal修饰符。比如我们开发了一个模块给别人使用,但是有一些函数只允许在模块内部调用,不想暴露给外部,就可以将这些函数声明成internal;
知识点8:数据类(数据模型)
数据类通常占据着非常重要的角色,它们用于将服务器端或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。或许你听说过MVC、MVP、MVVM之类的架构模式,不管是哪一种架构模式,其中的M指的就是数据类。
数据类通常需要重写equals()、hashCode()、toString()这几个方法。其中,equals()方法用于判断两个数据类是否相等。hashCode()方法作为equals()的配套方法,也需要一起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。toString()方法用于提供更清晰的输入日志,否则一个数据类默认打印出来的就是一行内存地址。
这里我们新构建一个手机数据类,字段就简单一点,只有品牌和价格这两个字段。如果使用Java来实现这样一个数据类,代码就需要这样写:
/**
* Created by: PeaceJay
* Created date: 2021/10/25
* Description:
*/
//Java版本写法
//数据类通常需要重写get()/set()、equals()、hashCode()、toString()这几个方法
public class Cellphone {
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Cellphone(String brand, double price) {
this.brand = brand;
this.price = price;
}
//toString()方法用于提供更清晰的输入日志,否则一个数据类默认打印出来的就是一行内存地址
@NotNull
@Override
public String toString() {
return "Cellphone{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
//equals()方法用于判断两个数据类是否相等
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Cellphone cellphone = (Cellphone) o;
return Double.compare(cellphone.price, price) == 0 &&
Objects.equals(brand, cellphone.brand);
}
//hashCode()方法作为equals()的配套方法,也需要一起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public int hashCode() {
return Objects.hash(brand, price);
}
}
Java的写法就显得比较复杂了,来试试Kotlin:
/**
* Created by: PeaceJay
* Created date: 2021/10/25
* Description:
*/
//你没看错,只需要一行代码就可以实现了!
//神奇的地方就在于data这个关键字,当在一个类前面声明了data关键字时,
//就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参数帮你将equals()、hashCode()、toString()等,
//固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量。
data class CellphoneKt(val brand: String, val price: Double) {
init {
println("brand=$brand" + "price=$price")
}
}
只需要一行代码就可以实现了!就在于data这个关键字,当在一个类前面声明了data关键字时,就表明你希望这个类是一个数据类。
下面我们来测试一下这个数据类,在main()函数中编写如下代码:
fun main() {
//8、数据类
dataView()
}
//8、数据类
fun dataView() {
//在一个规范的系统架构中,数据类通常占据着非常重要的角色,
//它们用于将服务器端或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。
//或许你听说过MVC、MVP、MVVM之类的架构模式,不管是哪一种架构模式,其中的M指的就是数据类
//下面我们来测试一下这个数据类
val cellphoneKt1 = CellphoneKt("小米11 12+256",4299.00)
val cellphoneKt2 = CellphoneKt("红米K40 Pro+ 12+256",3699.00)
val cellphoneKt3 = CellphoneKt("红米K40 Pro+ 12+256",3699.00)
println(cellphoneKt1)
println("cellphoneKt2 equals cellphoneKt3 = " + (cellphoneKt2 == cellphoneKt3))
}
打印日志结果为:
知识点9:单例类
单例模式做为最常用、最基础的设计模式之一,它可以用于避免创建重复的对象,来看看Java版本:
/**
* Created by: PeaceJay
* Created date: 2021/10/25
* Description: Java写法单例
*/
public class Singleton {
//这段代码其实很好理解,首先为了禁止外部创建Singleton的实例,
//我们需要用private关键字将Singleton的构造函数私有化,
//然后给外部提供了一个getInstance()静态方法用于获取Singleton的实例。
//在getInstance()方法中,我们判断如果当前缓存的Singleton实例为null,
//就创建一个新的实例,否则直接返回缓存的实例即可,这就是单例模式的工作机制
private static Singleton instance;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void SingletonText(){
System.out.println("SingletonText");
}
}
调用单例类中的方法:
//调用单例类中的方法
Singleton singleton = new Singleton.getInstance();
singleton.SingletonText();
虽然Java中的单例实现并不复杂,但是Kotlin明显做得更好,它同样是将一些固定的、重复的逻辑实现隐藏了起来,只暴露给我们最简单方便的用法。在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可。现在我们尝试创建一个Kotlin版的Singleton单例类:
/**
* Created by: PeaceJay
* Created date: 2021/10/25
* Description:
*/
//在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可
object SingletonKt {
fun singletonText() {
println("is singletonText")
}
}
在main()函数中编写如下代码:
fun main() {
//9、单例类
singletonView()
}
//9、单例类
fun singletonView() {
SingletonKt.singletonText()
}
打印日志结果为:
知识点10:集合的创建与遍历
传统意义上的集合主要就是List和Set,再广泛一点的话,像Map这样的键值对数据结构也可以包含进来。
List集合用法
方法一,类似Java的写法:
val arr = ArrayList<String>()
arr.add("ABC")
arr.add("FGH")
arr.add("HJK")
//遍历集合
for (str in arr){
print("$str ")
}
println()
但是这种初始化集合的方式比较烦琐,为此Kotlin专门提供了一个内置的listOf()函数来简化初始化集合的写法需要注意的是,listOf()函数创建的是一个不可变的集合。
方法二,不可变
val listOf = listOf("ABC","FGH","HJK","ZXC")
for (str in listOf){
print("$str ")
}
println()
方法三、可变
创建一个可变的集合,使用 mutableListOf()函数
val mutableListOf = mutableListOf("ABC","FGH","HJK","ZXC")
mutableListOf.add("VBN")
for (str in mutableListOf){
print("$str ")
}
println()
打印日志结果为:
Set集合用法
Set集合的用法几乎与此一模一样,只是将创建集合的方式换成了setOf()和mutableSetOf()函数, 需要注意,Set集合中是不可以存放重复元素的,如果存放了多个相同的元素,只会保留其中一份,这是和List集合最大的不同之处。
val setOf = setOf("ABC", "ABC", "FGH", "HJK", "ZXC")
for (str in setOf) {
print("$str ")
}
println()
Map集合的用法
方法一、类似HashMap
val map = HashMap<String, Int>()
map.put("小米9", 2000)
map.put("小米10", 3000)
map.put("小米11", 4000)
Kotlin中并不建议使用put()和get()方法来对Map进行添加和读取数据操作, 而是更加推荐使用一种类似于数组下标的语法结构,比如向Map中添加一条数据就可以这么写。
方法二、Kotlin写法
val newMap = HashMap<String, Int>()
newMap["小米9"] = 2000
newMap["小米10"] = 3000
newMap["小米11"] = 4000
//读取数据这样写
val number = newMap["小米9"]
println("小米10 = $number")
这仍然不是最简便的写法,因为Kotlin提供了一对mapOf()和mutableMapOf()函数来继续简化Map的用法这里的键值对组合看上去好像是使用to这个关键字来进行关联的,但其实to并不是关键字,而是一个infix函数。
方法三、mapOf、mutableMapOf写法
val mapOf = mapOf("小米9" to 2000, "小米10" to 3000, "小米11" to 4000)
val mutableMapOf = mutableMapOf("小米9" to 2000, "小米10" to 3000, "小米11" to 4000)
//遍历map的数据
for ((str, pic) in mapOf) {
println("str = $str pic = $pic")
}
打印日志结果为:
知识点11:集合的函数式API
集合的函数式
集合的函数式API有很多个,重点学习函数式API的语法结构,也就是Lambda表达式的语法结构。使用集合的函数式API来实现:
Lambda写法 {参数名1:类型,参数名2,类型 -> 函数体}
maxByOrNull函数的工作原理是根据我们传入的条件来遍历集合,从而找到该条件下的最大值
推导Lambda写法,从繁到简
①我们不需要专门定义一个lambda变量,而是可以直接将lambda表达式传入maxBy函数当中
val listOf = listOf("abc1", "fgh12", "Hjk1234", "zxc123")
val maxLength2 = listOf2.maxByOrNull { str: String -> str.length }
②Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型
val maxLength = listOf.maxByOrNull { str -> str.length }
③当Lambda表达式的参数列表中只有一个参数时,不必声明参数名,可以使用it关键字来代替
val maxLength = listOf.maxByOrNull { it.length }
println("maxLength = $maxLength")
集合中的map函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成一个另外的值, 映射的规则在Lambda表达式中指定,最终生成一个新的集合。比如,这里我们希望让所有的参数都变成大写模式:
val map = listOf.map { it.toUpperCase() }
for (str in map) {
println(str)
}
打印日志结果为:
学习两个比较常用的函数式API——any和all函数。
any函数用于判断集合中是否至少存在一个元素满足指定条件,
all函数用于判断集合中是否所有元素都满足指定条件
//any函数就表示集合中是否存在大于10长度的参数
val any = listOf.any { it.length > 10 }
println("至少存在一个元素满足大于10:$any")
val all = listOf.all { it.length > 3 }
println("所有元素都满足大于3:$all")
打印日志结果为:
Java函数式API的使用
首先看看Java版本线程
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("Java Thread");
}
}).start();
这里使用了匿名类的写法,我们创建了一个Runnable接口的匿名类实例,并将它传给了Thread类的构造方法,最后调用Thread类的start()方法执行这个线程。而如果直接将这段代码翻译成Kotlin版本:
Thread(object : Runnable {
override fun run() {
println("Thread Runnable")
}
}).start()
由于Kotlin完全舍弃了new关键字,因此创建匿名类实例的时候就不能再使用new了,而是改用了object关键字。再对以上代码进行精简:
Thread(Runnable {
println("Thread Runnable")
}).start()
因为Runnable类中只有一个待实现方法,即使这里没有显式地重写run()方法,Kotlin也能自动明白Runnable后面的Lambda表达式就是要在run()方法中实现的内容。还能继续精简:
Thread {
println("Thread Runnable")
}.start()
另外,如果一个Java方法的参数列表中有且仅有一个Java单抽象方法接口参数,我们还可以将接口名进行省略,这样代码就变得更加精简了
知识点12:空指针检查
Android系统上崩溃率最高的异常类型就是空指针异常(NullPointerException),主要是因为空指针是一种不受编程语言检查的运行时异常,只能由程序员主动通过逻辑判断来避免,但即使是最出色的程序员,也不可能将所有潜在的空指针异常全部考虑到。
然而,Kotlin却非常科学地解决了这个问题,它利用编译时判空检查的机制几乎杜绝了空指针异常。虽然编译时判空检查的机制有时候会导致代码变得比较难写,但是不用担心,Kotlin提供了一系列的辅助工具,让我们能轻松地处理各种判空情况,直接写doStudy(null)会报错,那么允许参数为空就需要写成student: StudentBean?,如下所示:
fun nullView() {
/**允许student参数为空,Kotlin会进行空指针检查,如下写法会抛出异常,在参数后面增加?,可以null检查*/
doStudy(null)
}
fun doStudy(student: StudentBean?) {
//代码也可简化为student?.readBooks()
student?.readBooks()
student?.doHomeWork()
student?.newDoHomeWork()
}
接下来我们通过一个具体的例子来结合使用?.和?:这两个操作符,从而让你加深对它们的理解。比如现在我们要编写一个函数用来获得一段文本的长度,使用传统的写法就可以这样写:
//12、空指针检查
fun nullView() {
println("长度 = " + getTextLength("200"))
println("长度 = " + getNewTextLength("2000"))
}
//编写一个函数用来获得一段文本的长度,允许为null
fun getTextLength(text: String?): Int? {
return text?.length
}
//判空辅助工具?:
//获得一段文本的长度,允许为null简化后
//这里我们将?.和?:操作符结合到了一起使用,首先由于text是可能为空的,
//因此我们在调用它的length字段时需要使用?.操作符,而当text为空时,
//text?.length会返回一个null值,这个时候我们再借助?:操作符让它返回0
fun getNewTextLength(text: String?) = text?.length ?: 0
这段代码看上去也并不复杂,但是我们却可以借助操作符?:让它变得更加简单。
打印日志结果为:
不过Kotlin的空指针检查机制也并非总是那么智能,有的时候我们可能从逻辑上已经将空指针异常处理了,但是Kotlin的编译器并不知道,这个时候它还是会编译失败。观察如下的代码示例:
如果我们想要强行通过编译,可以使用非空断言工具!!:
var content: String? = "null"
fun nullView() {
//这段代码一定是无法运行的。因为printUpperCase()函数并不知道外部已经对content变量进行了非空检查,
if (content != null) {
//在调用toUpperCase()方法时,还认为这里存在空指针风险,从而无法编译通过
//content.toUpperCase()
//如果我们想要强行通过编译,可以使用非空断言工具
content!!.toUpperCase()
}
}
知识点13:字符串内嵌表达式
Kotlin从一开始就支持了字符串内嵌表达式的功能,弥补了Java在这一点上的遗憾。
Kotlin允许我们在字符串里嵌入${}这种语法结构的表达式。
val a = "and"
//当表达式中仅有一个变量的时候,还可以将两边的大括号省略
val str = "Get up $a breathe every day"
println(str)
val map = HashMap<String, Int>()
map["小米11"] = 4000
//当表达式中不止一个变量的时候,需要增加大括号
val mapName = "手机售价${map["小米11"]}"
println(mapName)
打印日志结果为:
函数的参数默认值,一个非常有用的小技巧,给函数设定参数默认值, 我们可以在定义函数的时候给任意参数设定一个默认值, 这样当调用此函数时就不会强制要求调用方为此参数传值,在没有传值的情况下会自动使用参数的默认值:
//13、字符串内嵌表达式
fun embedStrView() {
strTest("strTest")
//类型不匹配
//strTest(100)
/**Kotlin提供了另外一种神奇的机制,就是可以通过键值对的方式来传参,从而不必像传统写法那样按照参数定义的顺序来传参*/
strTest(int = 200, str = "strTest")
}
fun strTest(str: String = "", int: Int = 10) {
println("str=$str int=$int")
}
这时如果想让int参数使用默认值该怎么办呢?模仿刚才的写法肯定是行不通的,因为编译器会认为我们想把字符串赋值给第一个num参数,从而报类型不匹配的错误。
Kotlin提供了另外一种神奇的机制,就是可以通过键值对的方式来传参,从而不必像传统写法那样按照参数定义的顺序来传参:
总结
在这一天里,我们全面学习了Kotlin编程中最主要的知识点,包括变量和函数、逻辑控制语句、面向对象编程、Lambda编程、空指针检查机制,等等,以上知识点掌握,有足够的实力使用Kotlin来学习Android程序开发了。