Kotlin基础

1.基本要素:函数和变量

函数

语句和表达式:

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

  • 表达式:有值,能作为另一个表达式的一部分使用
  • 语句:无值,总是包围着它的代码块中的顶层元素

在Java中,所有控制结构都是语句。
在Kotlin中,除了循环以外的大多数控制结构都是表达式。
在Java中,赋值是表达式,在Kotlin中则是语句。这有助于避免比较和赋值之间的混淆。

表达式函数体:

函数体由单个表达式构成的函数。

用表达式作为完整的函数体,并去掉花括号和return语句。

fun max(a: Int,b: Int) = if(a > b) a else b

变量

声明变量关键字由两个:

  • val:不可变引用,来自value。不能在初始化之后再次赋值,对应final变量
  • var:可变引用,来自variable。对应普通变量

默认情况下尽可能使用val关键字来声明变量。

使用不可变引用,不可变对象,无副作用的函数让你的代码更接近函数式编程风格。

字符串模板

val name = "world"
println("hello,$name")

和许多脚本语言一样,Kotlin可以在字符串字面值中引用局部变量,在变量前加上$即可。

这等价于Java中的字符串连接,编译后的代码创建了一个StringBuilder对象,并把常量和变量附加上去。

对象表达式和声明的区别

他俩之间只有一个特别重要的区别:

  • 对象表达式在我们使用的地方立即初始化并执行的

  • 对象声明是懒加载的,是在我们第一次访问时初始化的。

2.类和属性

属性

值对象:只有数据没有其他代码的类。

在Java中,字段和其访问器的组合被叫做属性

在Kotlin中,属性是头等的语言特性,在类中声明一个属性和声明一个变量一样:使用valvar关键字。

自定义访问器

class Rectangle(val h: Int, val w: Int){val isSquare: Booleanget(){return h == w}
}

属性isSquare不需要字段来保存其值,它的值是每次访问属性的时候被计算出来的。

也可以写成表达式体get() = h == w

Kotlin源码布局:目录和包

Java把所有类组织成包,Kotlin也有类似的概念。

Kotlin不区分导入的是类还是函数,允许使用import关键字导入任何种类的声明。可以直接导入顶层函数的名称。

在Java中,要把类放到和包结构相匹配的文件与目录结构中。

在Kotlin中则不需要,可以把多个类放在同一个文件中,文件的名字还可以随意选择。也没有对磁盘上源文件的布局强加任何限制。包的层级结构不需要遵循目录的层级结构。

3.表示处理和选择:枚举和“when”

声明枚举类

枚举并不是值的列表,可以给枚举类声明属性和方法。

enum class Color(val r: Int, val g: Int, val b: Int
) {RED(255, 0, 0), ORANGE(255, 165, 0),YELLOW(255, 255, 0), GREEN(0, 255, 0), BLUE(0, 0, 255),INDIGO(75, 0, 130), VIOLET(238, 130, 238);fun rgb() = (r * 256 + g) * 256 + b
}fun main(args: Array<String>) {println(Color.BLUE.rgb())
}

当你声明了枚举类的属性,那么声明枚举常量的时候,必须提供此枚举常量的属性值。

**Kotlin中唯一必须使用分号的地方:**在枚举类中,定义方法之前,用分号把常量和方法隔开。

使用“when”处理枚举类

Java中switch语句,在Kotlin中对应的结构是when

when是一个有返回值的表达式,因此可以直接写一个返回when表达式的表达式体函数。

enum class Color {RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}fun getMnemonic(color: Color) =when (color) {Color.RED -> "Richard"Color.ORANGE -> "Of"Color.YELLOW -> "York"Color.GREEN -> "Gave"Color.BLUE -> "Battle"Color.INDIGO -> "In"Color.VIOLET -> "Vain"}fun getWarmth(color: Color) = when(color) {Color.RED, Color.ORANGE, Color.YELLOW -> "warm"Color.GREEN -> "neutral"Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
}fun main(args: Array<String>) {println(getMnemonic(Color.BLUE))
}

和Java不一样你不需要写break语句,并且可以把多个值合并到同一个分支。

在“when”结构中使用任意对象

when允许使用任何对象作为分支条件。

fun mix(c1: Color, c2: Color) =when (setOf(c1, c2)) {setOf(RED, YELLOW) -> ORANGEsetOf(YELLOW, BLUE) -> GREENsetOf(BLUE, VIOLET) -> INDIGOelse -> throw Exception("Dirty color")}fun main(args: Array<String>) {println(mix(BLUE, YELLOW))
}

使用不带参数的“when”

上面一个例子中的代码效率有点低,因为每次调用它都会创建一些Set实例。

可以换一种方式重写:

fun mixOptimized(c1: Color, c2: Color) =when {(c1 == RED && c2 == YELLOW) ||(c1 == YELLOW && c2 == RED) ->ORANGE(c1 == YELLOW && c2 == BLUE) ||(c1 == BLUE && c2 == YELLOW) ->GREEN(c1 == BLUE && c2 == VIOLET) ||(c1 == VIOLET && c2 == BLUE) ->INDIGOelse -> throw Exception("Dirty color")}

若没有给when表达式提供参数,则分支条件就是任意的布尔表达式。

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

接下来用一个函数做例子,此函数要求完成 (1+2)+4 的算术表达式的求值。

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Exprfun eval(e: Expr): Int {if (e is Num) {val n = e as Numreturn n.value}if (e is Sum) {return eval(e.right) + eval(e.left)}throw IllegalArgumentException("Unknown expression")
}fun main(args: Array<String>) {println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
}

上面的代码展示了一种简单的类结构来表达这种表达式编码方式:Expr接口和其实现类NumSum

注意Expr接口没有声明任何方法,他只是一个标记接口,用来给不同种类的表达式提供一个公共的类型。

在Kotlin中,使用 is 检查来判断一个变量是否为某种类型。

is 检查和Java中的 instanceOf 相似。但是Kotlin中若你检查过某变量的类型,后面再使用它就不需要转换了。

编译器为你执行了类型转换,这种行为称为智能转换

智能转换只在变量经过is检查且之后不再发生变化的情况下有效。当你对一个类的属性进行智能转换的时候,这个属性必须是val属性,且不能有自定义的访问器。否则每次对属性的访问是否都能返回同样的值将无从验证。

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

重构:用“when”代替“if”

Kotlin没有三元运算符,因为if表达式有返回值。

这意味着可以用表达式体语法重写eval函数。

fun eval(e: Expr): Int =if (e is Num) {e.value} else if (e is Sum) {eval(e.right) + eval(e.left)} else {throw IllegalArgumentException("Unknown expression")}

若if分支只有一个表达式,花括号可以省略。

若if分支是代码块,代码块中最后一个表达式会被作为结果返回。

接下来使用when来重写:

fun eval(e: Expr): Int =when (e) {is Num ->e.valueis Sum ->eval(e.right) + eval(e.left)else ->throw IllegalArgumentException("Unknown expression")}

when表达式并不仅限于检查值是否相等,它还允许你检查实参值的类型。

代码块作为“if”和“when”的分支

分支体是代码块,代码块中最后一个表达式会被作为结果返回。

fun evalWithLogging(e: Expr): Int =when (e) {is Num -> {println("num: ${e.value}")e.value}is Sum -> {val left = evalWithLogging(e.left)val right = evalWithLogging(e.right)println("sum: $left + $right")left + right}else -> throw IllegalArgumentException("Unknown expression")}

规则:代码块中最后的表达式就是结果

此规则对try主体和catch子句也有效。

此规则对常规函数不成立。一个常规函数要么具有不是代码块的表达式函数体,要么具有包含显示return语句的代码块函数体。

4.迭代事物:“while”循环和“for”循环

while循环和Java中的没有区别。

for循环和Java的for-each循环一致,其写法和for<item> in <elements> 和C#一样。

迭代数字:区间和数列

区间:两个值之间的间隔,使用..来表示区间。

val oneToTen = 1..10

Kotlin的区间是闭合的,结束值是区间的一部分。

若你能迭代区间中所有的值,这样的区间被称作数列

fun fizzBuzz(i: Int) = when {i % 15 == 0 -> "FizzBuzz "i % 3 == 0 -> "Fizz "i % 5 == 0 -> "Buzz "else -> "$i "
}fun main(args: Array<String>) {for (i in 100 downTo 1 step 2) {print(fizzBuzz(i))}
}

上述代码迭代了一个步长为2的递减数列。

迭代map

下面的程序将字符转换成二进制打印出来:

fun main(args: Array<String>) {val binaryReps = TreeMap<Char, String>()for (c in 'A'..'F') {val binary = Integer.toBinaryString(c.toInt())binaryReps[c] = binary}for ((letter, binary) in binaryReps) {println("$letter = $binary")}
}

..也可以创建字符区间。这里从A迭代到F,包括F。

for循环允许展开迭代中的集合的元素,并把展开的结果存储到了两个独立变量letterbinary中。

可以用这样的展开语法在迭代集合的同时跟踪当前项的下标。

下面的代码遍历的list并打印出下标:

  val list = arrayListOf("10", "11", "1101")for ((index, element) in list.withIndex()) {println("$index : $element")}

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

使用in运算符来检查一个值是否在区间中,或者其逆运算,!n,检查不在区间中。

下面的代码检查一个char是数字还是字母:

fun recognize(c: Char) = when (c) {in '0'..'9' -> "It's a digit!"in 'a'..'z', in 'A'..'Z' -> "It's a letter!"else -> "I don't know…​"
}fun main(args: Array<String>) {println(recognize('8'))
}

区间不限于数字和字符,只要支持实例比较操作(实现了java.lang.Comparable接口),就能创建这一种类型的对象区间。

如果是这样的区间,并不能列举出这个区间中的所有对象。

比如我们不能列举出“Java”和“Kotlin”之间所有的字符串。

但是我们任然可以用in运算符检查一个对象是否属于这个区间。

5.Kotlin中的异常

Kotlin的异常处理大体上和Java一致。Kotlin中的throw结构是一个表达式,能作为另一个表达式的一部分使用。

“tyr”“catch”和“finally”

下面的代码从给定文件中读取一行,解析成数字并返回值;若不是有效数字则返回null

fun readNumber(reader: BufferedReader): Int? {try {val line = reader.readLine()return Integer.parseInt(line)}catch (e: NumberFormatException) {return null}finally {reader.close()}
}fun main(args: Array<String>) {val reader = BufferedReader(StringReader("239"))println(readNumber(reader))
}

和Java最大的区别是throws子句没有出现在代码中。

和其他许多现代JVM语言一样,Kotlin并不区分受检异常和未受检异常。不用指定函数抛出的异常,可以处理也可以不处理异常。

“try”作为表达式

修改上面的例子如下:

fun readNumber(reader: BufferedReader) {val number = try {Integer.parseInt(reader.readLine())} catch (e: NumberFormatException) {return}println(number)
}fun main(args: Array<String>) {val reader = BufferedReader(StringReader("not a number"))readNumber(reader)
}

try关键字引入了一个表达式,可以把它的值赋给一个变量。

return语句放在catch代码块中,因此该函数的执行在catch代码块之后不会再继续。

如果你需要返回值,可以将return替换为null,最后会打印出null

6.小结

  • fun关键字用来声明函数,valvar分别声明只读变量和可变变量
  • 字符串模板:在变量前加上$或者用${}包围一个表达式,来把值注入字符串
  • ifwhentry catch都是带返回值的表达式
  • 检查变量类型之后不必再显示的转换,编译器用智能转换自动帮你完成
  • ..会创建一个区间,还可以使用in!n运算符来检查值是否属于区间
  • Kotlin不要求你声明函数可以抛出的异常

《Kotlin实战》读书笔记第二章相关推荐

  1. 《计算传播学导论》读书笔记——第二章文本分析简介

    <计算传播学导论>读书笔记--第二章文本分析简介 第一节 文本分析研究现状 常用文本挖掘技术 第二节 文本分析与传播学研究 (一)为什么文本挖掘技术逐渐受到传播学者的关注 (二)不同文本分 ...

  2. 诙谐有趣的《UVM实战》笔记——第二章 一个简单的UVM验证平台

    前言 某天白天在地铁上听鬼故事,结果晚上要睡觉时,故事里的情节都历历在目,给我鸡皮疙瘩起的~ 不过我倒是没有吓得睡不着,而是转念一想,为啥我学知识忘得很快,随便听的鬼故事却记得这么清楚咧? 那如果能像 ...

  3. In-memory Computing with SAP HANA读书笔记 - 第二章:SAP HANA overview

    本文为In-memory Computing with SAP HANA on Lenovo X6 Systems第二章SAP HANA overview的读书笔记. 本章最重要的部分是SAP HAN ...

  4. C++ Primer Plus读书笔记第二章

    自学了一段时间的C++打算还是要系统的整理一下一些知识点,让学习思路更清晰,不然老是学一点忘一点,这个读书笔记用来记录这段时间对C++ Primer Plus一书中知识点的记录,尽量会写的详细一点.直 ...

  5. 《软件测试经验与教训》读书笔记---第二章

    <软件测试经验与教训>读书笔记--目录 第一章 测试员的角色 第二章 按测试员的方式思考 第三章 测试手段 第四章 程序错误分析 第五章 测试自动化 第六章 测试文档 第七章 与程序员交互 ...

  6. 计算机网络(第五版 作者:AndrewS.Tanenbaum David J.Wetherall 清华大学出版社)读书笔记----第二章的学习

    计算机网络第二章--物理层读书笔记 1.物理层是网络的技术设置,物理层的材质和带宽决定了最大的传输速率. 2.传输介质的分类:引导性(有线介质)和非引导性(无线介质). (1)有线介质:磁介质.双绞线 ...

  7. 《辛雷学习方法》读书笔记——第二章 心态

    第二章 心态   (1)保持良好心态:学习时保持良好心态,你才能比较容易入门.深入掌握知识.灵活运用知识.学习时始终保持着轻松愉悦振奋的心情,你就容易产生学习心得,更容易灵活运用. (2)爱情对心态影 ...

  8. 《暗时间》读书笔记--第二章 进度条,第三章 有效记忆和学习

    第二章 进度条 要点: 进度条的例子 过早的退出 专注和持之以恒 饿死在甘草间的驴子 我的总结: 开篇作者讲了一个进度条的例子,我们的生活中充满着各种各样的进度条,工作的之前我们要做工作计划,要指定T ...

  9. 【编程珠玑】读书笔记 第二章 算法

    2013-07-11 22:00:28 第二章 算法 本章围绕三个问题进行算法讨论,包括元素的查找.字符串的旋转.以及变位词的查找. 下面给出了实现代码.以及测试结果. 问题一 查找不存在的元素 思路 ...

  10. PHP核心技术与最佳实践 读书笔记 第二章 面向对象的设计原则

    2019独角兽企业重金招聘Python工程师标准>>> 第二章 面向对象的设计原则 2.1 面向对象设计的五大原则 单一职责原则 接口隔离原则 开放-封闭原则 替换原则 依赖倒置原则 ...

最新文章

  1. 二分法在算法题中的4种常见应用(cont.)
  2. FreeSWITCH在呼叫失败的情况下如何播放语音提示
  3. [转载] 杜拉拉升职记——30 我保证以后一直对你好
  4. 30. 多线程编程之threading模块
  5. 数学图形之克莱因瓶(klein bottle)
  6. 社交产品后端架构设计--转载
  7. Python之fastai:fastai库的简介、安装、使用方法之详细攻略
  8. web app会遇到那些问题
  9. 机器学习之决策树(下)
  10. Vista系统自带IIS 7.0设置技巧详解
  11. 【HDU - 2546】饭卡 (dp,0-1背包,贪心思想)
  12. 【液晶模块系列基础视频】3.2fatfs接口函数的使用2
  13. shell脚本导出oracle数据库,Shell脚本备份恢复Oracle数据库简单示例
  14. 确定填充介质的矩形波导单模传输TE10波的工作频率
  15. tcpdump + mk-query-digest 分析mysql
  16. JSP中用request.setAttribute()后,在action中为什么取不到值?
  17. 利用组策略进行软件分发
  18. JS操作iframe元素
  19. 第08章节-Python3.5-Django工程创建 7
  20. 随笔记--Pycharm中Terminal字体大小的设置

热门文章

  1. BZOJ 3698 XWW的难题:有上下界的最大流
  2. 天秤座男人对爱情的态度(图
  3. 情人节买什么礼物比较好呢?最实用的情人节礼物分享
  4. 开开眼界 盖茨2013年的书单
  5. 免费开源动画制作软件推荐(新手必备)
  6. iPhone X适配之MJ上拉加载更多的适配
  7. 比特大陆内部究竟发生了什么?
  8. html页面滚动条监听事件,滚动条的scroll事件
  9. 中地恒达无线倾角加速度计
  10. 从普通 Msconfig 启动选择转为选择性启动