一、 函数与变量
函数
1. 函数特征
fun 关键字
参数声明 如:arg1:Int
,arg2:Array<String>
函数不一定要放在类中,可以放在文件的最外层
数组也是类
有些方法可以简化,如 println 可以直接使用
可以省略末尾的分好
返回值同参数声明,同类字段声明都是冒号隔开
函数体是单个表达式的可以省略花括号
可以推出来的类型可以省略
// fun为关键字,main为函数名,args为入参,Array<String>为入参类型, println 为省略的方法
fun main(args:Array<String>){ // 返回值为空,则不写
println("Hello world!")
}
//fun 函数名(参数名:参数类型,...): 返回值类型{
// 函数体
//}
fun max(a:Int, b:Int) : Int{
return if(a>b) a else b
}
// 上面的例子中,if(a>b) a else b为表达式,并且返回值可根据表达式推出来,所以可简化为
fun max(a:Int, b:Int) = if(a>b) a else b
2.表达式与语句
- 表达式 有值,且能作为另一个表达式的一部分使用。除了语句中的其他的控制结构都是表达式。 如 if(a>b) a else b
- 语句 没有值,包围着代码块中的顶层元素。 如: for , do , do/while, 赋值操作
变量
1. 变量特征
// var/val 变量名 : 变量类型 = 值(默认值)
// var 可变, val 不可变(只可赋值一次)
// 变量类型 如果在声明时就给出默认值,可省略。 省略时, 整型默认类型为Int,浮点数默认类型为 Double
val name : String = "Daisy"
2. var 与 val
- val 不可变,只可赋值一次,但可以根据不同的条件进行不同的赋值。 val 的引用自身不可变,但它指向的对象可能是可变的。
- var 只可改变值,不可改变其类型
val a : Int
if(a 从 0 开始){
a = 0
} else a = 1
字符串模板
其内部实现,创建了个StringBuilder对象,并把常量部分和变量附加上去
fun main (args : Array<String>){
val name = if(args.size() > 0) args[0] else "Null"
println("Hello, $name !") // 字符串模板,通过$ 进行转义, 使用变量name 的值
if(if(args.size() > 0)){
println("Hello, ${args[0]}!") // 字符串模板,通过$ 进行转义,花括号中为表达式
}
println("Hello, ${if(args.size() > 0) args[0] else "Null"}!")// 字符串模板,通过$ 进行转义,花括号中为表达式,即使里面有双引号,但在表达式范围内仍然可以使用
println("Hello, \$name !") // 想要输出 $ 符号,前面加“\”
}
二、类和属性
最简单的类
- 只有数据没有其他代码的类 被称为 值对象
- 在Kotlin中默认为 public 的,所以 public可省略
// 值对象 val name : String 为属性
class Person(val name : String, var isMarried: Boolean)
属性
字段及其访问器的组合被叫作属性, 而在Kotlin中,属性是头等的语言特性,完全代替了字段和访问器方法。 声明属性与声明变量一样,使用 var/val 关键字,var 只读,val 可变
- val 只读,只有get方法,可通过 getName() 或者 .name 访问
- var可读写,有get set 方法
- 属性名称为 is打头的,getter方法不会增加其他的前缀,setter方法中,is替换为set
自定义访问器
class Student(val name: String, val age: Int) {
val isAdult: Boolean // 只读
// get() {
// return age >= 18
// }
get() = age >= 18
var beginName: String
set(value) {
beginName = value + "Test" // 此处"=" 在kotlin中是语句不是表达式 所以不能更改为 set(value)= 的格式
}
// get() {
// return if (beginName.length < 4) beginName else beginName.substring(0, beginName.length - 4)
// }
get() = if (beginName.length < 4) beginName else beginName.substring(0, beginName.length - 4)
}
目录和包
package com.example.wangyy.kotlintest // 包声明, 同在一个包下面的,可直接使用,不需要导入
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
class MainActivity : AppCompatActivity() {
}
- 同在一个包下面的,可直接使用,不需要导入
- Kotlin 不区分导入的是类还是函数
- 应该毫不犹豫的把多个类放进同一个文件夹中,特别是很小的类
枚举和”when”
声明枚举类
enum class Color(val red: Int, val green: Int, val blue: Int, val alpha: Int // 声明枚举常量属性
) {
RED(255, 0, 0, 0), // 在每个常量创建时,指定属性值
GREEN(0, 255, 0, 0),// 逗号隔开
BLUE(0, 0, 255, 0),
BLACK(0, 0, 0, 0),
WHITE(255, 255, 255, 0); //分号不能去掉 此处为Kotlin唯一使用分号的地方
fun rgla(): Int { // 枚举定义的方法
return red + green + blue + alpha
}
}
使用“when”处理枚举类
在”when”结构中使用任意对象
import com.example.wangyy.kotlintest.Color.* // 导入枚举常量
fun getColorMnemonic(color: Color) = // 直接返回"when"表达式
when (color) {
Color.BLUE -> "BLUE" // 如果颜色和枚举常量相等,则返回对应的字符串
WHITE -> "WHITE" // ***导入枚举常量***后不用限定词就可以访问
Color.RED, Color.GREEN, Color.BLACK -> "Red" // 可在一个when分支上合并多个选项
else -> throw Exception("Dirty color") // 如果没有任何其他分支匹配就会执行(此处为不同的对象)
}
使用不带参数的when
如果没有给when表达式提供参数,分支条件就是任意的布尔表达式。
fun getColor(c1: Color, c2:Color) =
when{
(c1 == RED && c2 = YELLOW) || (c2 == RED && c1 = YELLOW) -> ORANGE
(c1 == BLUE&& c2 = YELLOW) || (c2 == BLUE&& c1 = YELLOW) -> GREEN
(c1 == BLUE&& c2 = VIOLET) || (c2 == BLUE&& c1 = VIOLET) -> INDIGO
else -> throw Exception("Dirty color")
}
智能转换:合并类型检查和转换
重构: 用“when”代替“if”
interface Expr
class Num(val value: Int) : Expr
class Sum(val right: Expr, val left: Expr) : Expr
fun eval(e:Expr) : Int =
if(e is Num){
val n = e as Num // as用于特定类型的转换, 但是此处为多余
return n.value
} else if(e is Sum){
return eval(e.left) + eval(e.right) // 在Kotlin中使用is 来检查判断一个变量是否是某中类型。 通 instanceOf(Java), 但是检查过后,可以直接使用该类型,不需要再进行强制转换。
} else {
throw Exception("Unknown expression") // throw是一个表达式,可以作为另一个表达式的一部分使用
}
//用“when”代替“if”
fun eval(e: Expr): Int =
when {
e is Num -> e.value // 检查实参类型的when 分支
e is Sum -> { // 代码块作为 “if” 和 "when" 的分支
println("e is Sum!") // 只能放在最后一个表达式之前
eval(e.right) + eval(e.left) // 代码块的最后一个表达式就是结果
}
else -> 0
}
fun main(args: Array<String>) {
println(eval(Sum(Sum(Sum(Num(1), Sum(Num(2), Num(3))), Num(4)), Num(5))))
}
// 15
迭代事务:”while”循环和“for”循环
“while”循环 同java
while(condition){ //condition为true时执行循环体
/*...*/
}
do { // 至少执行一次
/*...*/
} while(condition) //condition为true时执行循环体
迭代数字:区间和数列
区间的本质就是两个值之间的间隔,这两个值通常是数字,或者字母:一个起始值,一个结束值。使用..运算符来表示区间
val oneToTen = 1..10 // 区间是闭合的[] 两边都包含,此处为1到10
如果你能迭代区间中的所有的值,这样的区间被称为 数列
fun fuzzBuzz(i : Int) = when{
i%15 == 0 ->"fuzzBuzz "
i%3 == 0 ->"fuzz "
i%5 == 0 ->"Buzz "
else -> "$i "
}
>>> for(i in 1..100){ // 从1 到100 使用in来迭代区间或者集合
... print(fuzzBuzz(i))
... }
>>> for(i in 100 downTo 1 step 2){ // 从100 到1,间隔为2
... print(fuzzBuzz(i))
... }
>>> for(i in 1 until 100){ // until 关键字 等于 1..99
... print(fuzzBuzz(i))
... }
迭代map
val maps = TreeMap<Char, String>()
for (c in 'A' until 'G') { // 等同于 for(c in A..F)
maps[c] = Integer.toBinaryString(c.toInt())
}
val hashMaps = hashMapOf('A' to 1, 'B' to 2, 'C' to 3, 'D' to 4)
hashMaps['E'] = 5 // 使用map[key] = value 赋值
println("" + hashMaps['E']) // 通过 map[ket] 读取值
for ((key, value) in maps) {
println("$key = $value")
}
for ((key, value) in hashMaps) {
println("$key = $value")
}
val list = arrayListOf("01", "001", "0001")
for ((key, value) in list.withIndex()) { //withIndex() 下标
println("$key = $value")
}
//5
//A = 1000001
//B = 1000010
//C = 1000011
//D = 1000100
//E = 1000101
//F = 1000110
//A = 1
//B = 2
//C = 3
//D = 4
//E = 5
//0 = 01
//1 = 001
//2 = 0001
使用“in”检查集合和区间的成员
使用“in”运算符来检查一个值是否在区间中,或者用“!in”来检查这个值是否不在区间中
in”运算符 和 “!in” 也使用与when表达式(上面讲when的时候有例子)
val list = arrayListOf("01", "001", "0001")
val set = setOf("01", "001")
val set2 = setOf<String>("01", "001")
println("Is 00001 in list? ${"00001" in list}")
println("Is 0001 in list? ${"0001" in list}")
println("Is 0001 in set? ${"0001" in set}")
println("Is 001 in set ? ${"001" in set}")
println(1.5F in 1..2) // 等同于 1.5F >=1 && 1.5F<=2
// 结果:
// Is 00001 in list? false
// Is 0001 in list? true
// Is 0001 in set? false
// Is 001 in set? true
// true
Kotlin中的异常
val percentage = if(a in 0..100){
a // 此时percentage 被赋值为a
} else {
throw Exception("Unknown expression") // Exception不需要new关键字。 throw是一个表达式,可以作为另一个表达式的一部分使用。 此时 异常将会被抛出,percentage不会被赋值
}
try、catch、finally
fun readNumber(reafer:ButteredReader) : Int{ // 不用显示的指定这个函数可能抛出异常
try{
val line = reader.readLine()
return Integer.parseInt(line)
} catch(e :NumberFormatException){ // 异常类型在右边
return null
} finally{ // finally的作用和Java中的一样
reader.close()
}
}
Kotlin并不区分受检异常和未受检异常
try作为表达式
fun readNumber(reafer:ButteredReader) {
val number = try{
val line = reader.readLine()
Integer.parseInt(line)
} catch(e :NumberFormatException){
//return // 用return 当不是数字的时候,什么也没输出
null // 返回null时,下面的println 会输出 null
}
println(number)
}
小结
fun 关键字用来声明函数,val关键字和var关键字分别用来声明只读变量和可变变量
字符串模板帮助你避免繁琐的字符串连接。 前缀或者 {} 包围一个表达式
值对象在Kotlin中以简洁的方式标识 class Person(var name : String)
if 是带返回值的表达式
when表达式类似于 switch 但更强大
检查过变量的类型之后(is),不比显示的转换(as)。智能转换
for while do-while 与java类似。for循环Kotlin更方便,使用in关键字
1..5为1到5的区间,使用in 和 !in 运算符来检查值是否属于区间
Kotlin中的异常处理和java相似,除了Kotlin不要求声明函数可以抛出的异常