【Kotlin学习】Kotlin基础知识

函数与变量

函数

一个普通的函数基本结构
【Kotlin学习】Kotlin基础知识_第1张图片

语句和表达式
在kotlin中,if是表达式而不是语句。

语句和表达式的区别

表达式有值,并且能作为另一个表达式的一部分使用
而语句总是包围着它的代码块中的顶层元素,且没有自己的值

在java中所有的控制结构都是语句,在kotlin中除了循环(for while do/while)之外大多数控制结构都是表达式
另一方面,java中的赋值操作是表达式,在kotlin中却是语句

表达式函数体

可以让前面的函数变得更简单,因为它的函数体是由单个表达式构成的,可以用这个表达式作为完整的函数体,并去掉花括号的return语句

在这里插入图片描述

如果函数体写在花括号中,我们就说这个函数有代码块体。如果它返回了一个表达式,它就有表达式体。

继续简化,省略返回类型

在这里插入图片描述

对于表达式体函数来说,编译器会分析作为函数体的表达式,并把它的类型作为函数的返回类型,即使没有显式写出返回类型,这种分析叫做类型推导。
注意!只有表达式体函数的返回类型可以省略。对于有返回值的代码块体函数,必须显式写出返回类型和return语句。

变量

在java中声明变量时以类型开始,在kotlin中因为许多变量声明的类型都可以忽略,所以在kotlin中以关键字开始,然后是变量名称,最后可以加上类型(可选)

在这里插入图片描述

和表达式体函数一样,如果不指定变量的类型,编译器会分析初始化器表达式的值,并把它的类型作为变量的类型。在该例子中,变量的初始化器42(在这里42这个值是初始化器)的类型是Int,那么变量就是Int,如果使用浮点数常量,那么它就是Double类型

如果变量没有初始化器则需要显式指定它的类型

在这里插入图片描述

如果不能提供可以赋给这个变量的值的信息,编译器就无法推断出它的类型

可变变量和不可变变量

val

不可变引用。使用val声明的变量不能再初始化之后再次赋值,对应java的final变量

var

可变引用。值可以被改变,对应非final变量

默认情况下应尽可能用val关键字来声明所有的kotlin变量,仅在必要的时候换成var。
在定义了val变量的代码块执行期间,val变量只能进行唯一一次初始化,但如果编译器能确保只有唯一一条初始化语句会被执行,可根据条件使用不同的值来初始化它。

【Kotlin学习】Kotlin基础知识_第2张图片

注意!尽管val引用自身是不可变的,但是它指向的对象可能是可变的

在这里插入图片描述

var关键字允许变量改变自己的值,但它的类型却是改变不了的

在这里插入图片描述

编译器只会根据初始化器来推断变量的类型,在决定类型的时候不会考虑后续的赋值操作

更简单的字符串格式化:字符串模板

在这里插入图片描述

如上图,kotlin可以让你在字符串字面值中引用局部变量,只需要在变量名称前加上字符$,表达式会进行静态检查,如果试着引用一个不存在的变量,代码不会编译。如果要在字符串中使用$,要使用转义字符\,
还可以引用更复杂的表达式,而不是仅限于简单的变量名称,只需要把表达式用花括号括起来。

在这里插入图片描述

类和属性

在kotlin中我们可以使用自动转换工具把java代码转换成kotlin代码

下图的Person即是我们要转换的对象

【Kotlin学习】Kotlin基础知识_第3张图片

转换之后

在这里插入图片描述

这种只有数据没有其他代码的类通常被叫作值对象

在kotlin中public是默认的可见性,所以可以省略

属性

在java中,字段和其访问器的组合常常被叫作属性
在kotlin中,属性是头等的语言特性,完全替代了字段和访问器方法

【Kotlin学习】Kotlin基础知识_第4张图片

基本上当你声明属性的时候你就声明了对应的访问器。访问器的默认实现非常简单,如果有需要可以自定义访问器。上图的类是一个字段都是私有的类,这些字段在构造方法中初始化并能通过对应的getter访问。这意味着在java和kotlin都能以同样方式使用这个类,不论它在哪里声明。

getter和setter的命名规则有一个例外,如果属性以is开头,getter不会增加任何前缀,setter会把is替换成set

在这里插入图片描述

在java中,使用person.setMarried(false)表示离婚
在kotlin中,可以写成person.isMarried=false

注意!
在java中定义的类一样可以使用kotlin的属性语法,java类中的getter可以被当成val属性在kotlin访问,而一对getter/setter可以被当成var属性访问。

自定义访问器

【Kotlin学习】Kotlin基础知识_第5张图片

属性isSquare不需要字段来保存它的值,他只有一个自定义实现的hetter,它的值是每次访问属性的时候算出来的。
可以使用不带花括号的完整语法:get()=height==width 它们唯一的差异是可读性

kotlin的控制结构

枚举和when

声明枚举类

在这里插入图片描述

enum是一个软关键字:只有当它出现在calss前面时才有特殊的意义,在其他地方可以把它当成普通名称使用。和java一样,枚举不是值的列表:可以给枚举类声明属性和方法

在这里插入图片描述

如果要在枚举类中定义任何方法,就要使用分号把枚举常量列表和方法定义分开。

使用when处理枚举类

和if相似,when是一个有返回值的表达式,所以可以写一个直接返回when表示式的表达体式函数

【Kotlin学习】Kotlin基础知识_第6张图片

不需要在每个分支都写上break语句,如果匹配成功,只有对应的分支会执行,也可以把多个值合并到同一个分支,只需要用逗号隔开这些值

【Kotlin学习】Kotlin基础知识_第7张图片

当导入Color类后可以直接使用它们的名称

在这里插入图片描述

【Kotlin学习】Kotlin基础知识_第8张图片

在when结构中使用任意对象

编译一个混合两种颜色的函数,举个例子

【Kotlin学习】Kotlin基础知识_第9张图片

kotlin标准函数库中有一个setOf函数可以创建一个Set,他会包含所有指定为函数实参的对象。这种集合的条目顺序并不重要,只要两个set包含相同的条目那么它们就是一样的,如果没有其他的分支满足条件,else分支会执行,我们能使用任何表达式做when的分支条件

使用不带参数的when

上方的函数如果调用很频繁,他就只得用另一种方式重写来避免创建额外的垃圾对象

【Kotlin学习】Kotlin基础知识_第10张图片

如果没有给when表达式提供参数,分支条件就是任意的布尔表达式,这样写的有点事不会创建额外的对象,缺点是更难理解

智能转换:合并类型检查和转换

编写一个函数对如(1+2)+4这样的算术表达式求值,我们可以把它们存储在一个树状结构中,书中的每个节点要么是一次求和要么是一个数字,Num永远是叶子节点,而Sum节点有两个子节点,他们是求和的两个参数。下图为示例

Expr接口

【Kotlin学习】Kotlin基础知识_第11张图片

Num类是一个简单的值对象,只有一个属性value并实现了Expr接口

【Kotlin学习】Kotlin基础知识_第12张图片

Sum运算的实参可以是任何Expr,也就是Num或者Sum

【Kotlin学习】Kotlin基础知识_第13张图片

eval

【Kotlin学习】Kotlin基础知识_第14张图片

在kotlin要用is检查一个变量是否属于某种类型。在java中,如果你已经检查过一个变量是某种类型并且要把它当作这种类型来访问其成员时,在检查之后还需要显式加上类型转换。如果最初的变量会使用超过一次,常常选择把类型转换的结果存储在另一个单独的变量里。而在kotlin中,编译器帮你完成了这些工作,如果你检查过一个变量是某种类型,后面就不再需要转换它,可以就把它当作你检查过的类型使用,事实上编译器为你执行了类型转换,这种行为称为类型转换

在我们编写的eval函数中,在检查过e是否为Num类型后,编译器就把它当成Num类型的变量解释。智能转换只在变量经过is检查且之后不再发生变化的情况下有效。当你对一个类的属性进行智能转换的时候,这个属性必须是一个val属性,而且不能有自定义访问器。否则每次对属性的访问是否都能返回同样的值将无从验证

as关键字来表示到特定类型的显式转换

重构eval函数使其更符合kotlin风格

【Kotlin学习】Kotlin基础知识_第15张图片

如果分支只有一个表达式,花括号是可以省略的。如果if分支是一个代码块,代码块中的最后一个表达式会被作为结果返回

继续重写

【Kotlin学习】Kotlin基础知识_第16张图片

代码块作为if和when的分支

【Kotlin学习】Kotlin基础知识_第17张图片

if和when都可以使用代码块作为分支体,这种情况下代码块最后一个表达式就是结果

规则
代码块中最后的表达式就是结果,在所有使用代码块并期望得到一个结果的地方成立。但这个规则对常规函数不成立。一个函数要么具有不是代码块的表达式函数体,要么是具有包含显式return的代码块函数体

while循环和for循环

kotlin有while和dowhile循环,语法和java中没什么不同

在kotlin中没有常规的java的for循环,kotlin使用了区间概念。区间本质上就是两个值之间的间隔,这两个值通常是数字:一个起始值,一个结束值,用…运算符来表示区间

在这里插入图片描述

注意kotlin的区间是包含的或者闭合的,意味着第二个值始终是区间的一部分
整数区间能做的最基本事情就是循环迭代器中所有的值。如果你能迭代区间中所有的值,这样的区间被称为数列

例子

【Kotlin学习】Kotlin基础知识_第18张图片

结果

【Kotlin学习】Kotlin基础知识_第19张图片

修改循环条件:从100开始,把步长改为2,数到1为止

【Kotlin学习】Kotlin基础知识_第20张图片

结果部分截图

【Kotlin学习】Kotlin基础知识_第21张图片

许多情况下迭代不包含指定结束值的半闭合区间更方便。使用until函数可以创建这样的区间。如for(x in 0 until size)等同于for(x in 0…size-1)

迭代map

【Kotlin学习】Kotlin基础知识_第22张图片

结果

【Kotlin学习】Kotlin基础知识_第23张图片

…语法不仅可以创建数字区间,还可创建字符区间。上图展示了for循环允许展开迭代中的集合的元素(在这里展开的是map的键值对集合),把展开的结果存储到了两个独立的变量中。而且访问和更新map不需要依靠get和set函数。

可以用这样的展开语法在迭代集合的同时跟踪当前项的下标,不需要创建一个单独的变量来存储下标并手动增加它

【Kotlin学习】Kotlin基础知识_第24张图片

结果

在这里插入图片描述

使用in检查集合和区间的成员

检查一个字符是否是字母

在这里插入图片描述

in和!in运算符也适用于when表达式

用in检查作为when分支

【Kotlin学习】Kotlin基础知识_第25张图片

区间也不仅限于字符。假如有一个支持实例比较操作的任意类(实现了Comparable接口),就能创建这种类型的对象的区间。

试想是否可以列举出"java"和"kotlin"之间所有字符串,答案是不能,但是仍然可以使用in运算符检查一个其他的对象是否属于这个区间

【Kotlin学习】Kotlin基础知识_第26张图片

in检查同样适用于集合

在这里插入图片描述

kotlin中的异常

异常处理语句的基本形式和java类似,抛出异常的方式也不例外。和java不同的是,kotlin中throw结构是一个表达式,能作为另一个表达式的一部分使用

【Kotlin学习】Kotlin基础知识_第27张图片

try-catch-finally语句

【Kotlin学习】Kotlin基础知识_第28张图片

和java最大区别就是throws没有出现在代码中,因为kotlin并不区分受检异常和未受检异常。不用指定函数抛出的异常,而且可以处理也可以不处理异常

try作为表达式

【Kotlin学习】Kotlin基础知识_第29张图片

try和if、when一样引入了一个表达式,可以把它的值赋给一个变量。不同于if,你总是需要用花括号把语句主主体括起来。和其他语句一样如果其主体包含多个表达式,那么整个try表达式的值就是最后一个表达式的值,该函数执行到catch便会停止,如果你想继续执行,catch子句也需要有一个值,它将是子句中最后一个表达式的值

【Kotlin学习】Kotlin基础知识_第30张图片

你可能感兴趣的:(Kotlin学习,学习,android,kotlin)