Kotlin入门

基本句法

定义包名

在源文件的顶部定义包名

package my.demo
import java.util.* 
// ...

Kotlin不要求匹配目录和包名:源文件可以放在文件系统任意的位置。

定义函数

下述函数定义了两个Int参数和一个Int的返回类型:

fun sum(a: Int, b: Int): Int { 
    return a + b 
}

kotlin函数可以根据表达式类容推断出返回类型:

fun sum(a: Int, b: Int) = a + b

函数返回Unit类型(相当于java中的void):

fun printSum(a: Int, b: Int) : Unit {
    println("sum of $a and $b is ${a + b}") 
}

Unit 返回类型可以省略:

fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}") 
}

定义本地变量

一次赋值(只读)本地变量:

val a: Int = 1 //立即分配
val b = 2 //Int型是被推断出
val c: Int
c = 3          //推迟赋值

可变变量

var x = 5 
x += 1

注释

同Java和JavaScript一样,Kotlin支持行注释和块注释。

// 这是单行注释

/* 这是多行的块注释 /* 嵌套注释 */ */

和Java不一样的地方在于,Kotlin中的块注释可以嵌套。

使用字符串模板

var a = 1 

// 模板中使用简单的名称
val s1 = "a is $a"

a = 2 

// 模板中使用随意的表达式
val s2 = "${s1.replace("is", "was")}, but now is $a"

使用条件表达式

fun maxOf(a: Int, b: Int): Int {
     if (a > b) {
        return a 
     } else {
        return b 
     } 
}

将if当做一个表达式

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

使用nullable和校验null

当一个引用可能是null值时,必须明确标记nullable

下述函数,当str没有保存一个整数时将返回null

fun parseInt(str: String): Int? { 
    // ...
}

使用一个函数,返回nullable值

fun printProduct(arg1: String, arg2: String) { 

    val x = parseInt(arg1) 
    val y = parseInt(arg2)

    // 使用`x*y`会产生错误,因为他们可能是空值。
    if (x != null && y != null) {
    // 做了空校验之后,x 和 y会自动转成非空值。 
        println(x * y) 
    } else {
        println("either '$arg1' or '$arg2' is not a number") 
    }
}

使用类型检查和类型自动转化

操作符 is 校验表达式是否是某个类型的实例,如果本地常量或属性经过明确的类型校验,他将没必要做明确的类型转换。

fun getStringLength(obj: Any): Int? {

    if (obj is String) { 
        // 这个分支中,obj已经自动转换成String类型
        return obj.length 
    }

    // 在类型检查分支外,obj还是Any类型
    return null
}

或者:

fun getStringLength(obj: Any): Int? { 
    if (obj !is String) return null

    // 这个分支中,obj已经自动转换成String类型
    return obj.length

}

更甚至:

fun getStringLength(obj: Any): Int? {
    // `obj` is automatically cast to `String` on the right-hand side of `&&` 
    //在执行&&右边运算时,obj 已经自动转换成String类型
    if (obj is String && obj.length > 0) { 
        return obj.length 
    }
    return null
}

使用for循环

val items = listOf<String>("apple","orange","kiwi")

for(item in items)
    println(item)

for(index in items.indices)
    println("item at $index is ${items[index]}")

使用while循环

val items = listOf<String>("apple","orange","kiwi")

var index = 0
while(index<items.size){
    println("item at $index is ${items[index]}")
    index++
}

使用when表达式

fun describe(obj: Any): String =
    when (obj) {
        1 -> "one"
        is Long -> "Long"
        "Hello" -> "Greeting"
        !is String -> "not String"
        else -> "Unknown"
    }

使用序列

用in操作符检查数字是否在序列中

val x = 9
val y = 10
if(x in 1..y+1)
    print("fits in range")

检查数字是否在序列外

val list = listOf<String>("a","b","c")

if(-1 !in 0..list.lastIndex)
    println("-1 is out of range")

if(list.size !in list.indices)
    println("list size is out of valid list indices range too")

迭代序列

for(index in 1..5)
    println("index = $index")

跳跃迭代

for(index in 0..10 step 2)
    println("index = $index")

for(index in 9 downTo 1 step 3)
    println("index = $index")

使用集合

迭代集合

val items = listOf<String>("apple", "orange", "kiwi")

for (item in items)
    println(item)

用in操作符检查集合是否包含指定对象

when { 
    "orange" in items -> println("juicy") 
    "apple" in items -> println("apple is fine too") 
}

使用lambda表达式过滤和转换集合

val items = listOf<String>("apple", "orange", "kiwi")
var it :String
items
    .filter { it.startsWith("a") } 
    .sortedBy { it } 
    .map { it.toUpperCase() } 
    .forEach { println(it) }

风格

创建DTOs(POJOs/POCOs)

data class Customer(val name: String, val email: String)

定义的Customer类有如下功能:

  • getters(var 变量还有setters)方法
  • equals()
  • hashCode()
  • toString()
  • copy()
  • component1() , component2()…(对应每个属性)

函数参数默认值

fun foo(a: Int = 0, b: String = "") { ... }

筛选list

val list = 1..5
val position = list.filter { x->x>3 }//position = [4,5]

或者简写:

val position = list.filter { x>3 }//position = [4,5]

插入字符串

println("Name $name")

检查实例

when (x) { 
    is Foo -> ... 
    is Bar -> ... 
    else -> ... 
}

遍历map/list

for ((k, v) in map) { 
    println("$k -> $v") 
}

k、v可以是任意类型

使用序列

for (i in 1..100) { ... } // 封闭式,包含100
for (i in 1 until 100) { ... } // 半封闭式,不包含100
for (x in 2..10 step 2) { ... } 
for (x in 10 downTo 1) { ... } 
if (x in 1..10) { ... }

只读list

val list = listOf("a", "b", "c")

只读map

val map = mapOf("a" to 1, "b" to 2, "c" to 3)

访问map

println(map["key"]) 
map["key"] = value //需要实现set方法

懒属性(lazy property)

val p: String by lazy { 
    // compute the string 
}

函数表达式

fun String.spaceToCamelCase() { ... }

"Convert this to camelcase".spaceToCamelCase()

创建单例

object Resource { 
    val name = "Name" 
}

if not null 简单表达

val files = File("Test").listFiles()

println(files?.size)

if not null and else 简单表达

val files = File("Test").listFiles()

println(files?.size ?: "empty")

如果空,执行声明

val data = ...

val email = data["email"] ?: throw IllegalStateException("Email is missing!")

如果非空执行

val data = ...

data?.let { ... // execute this block if not null 
}

返回when声明

fun transform(color: String): Int {
    return when (color) { 
        "Red" -> 0 
        "Green" -> 1 
        "Blue" -> 2 
        else -> throw IllegalArgumentException("Invalid color param value") 
    }
}

try/catch 表达式

fun test() {

    val result = try { 
        count() 
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e) 
    }
// .....

}

if 表达式

fun foo(param: Int) {
    val result = if (param == 1) { 
        "one" 
    } else if (param == 2) {
        "two" 
    } else {
        "three" 
    }
}

对返回Unit方法使用构建风格

fun arrayOfMinusOnes(size: Int): IntArray {
    return IntArray(size).apply { fill(-1) }
}

单表达式函数

fun theAnswer() = 42

等价于

fun theAnswer(): Int {
    return 42
}

还可以结合其他风格,形成更简短的语句。when 表达式为例:

fun transform(color: String): Int = when (color) { 
    "Red" -> 0
    "Green" -> 1
    "Blue" -> 2
    else -> throw IllegalArgumentException("Invalid color param value")
}

使用with,执行对象实例的多个方法

class Turtle {
    fun penDown(){}
    fun penUp(){}
    fun turn(degrees: Double){}
    fun forward(pixels: Double){}
}

val myTurtle = Turtle()

with (myTurtle) {
    penDown()
    for(i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}

使用java7 try 读取资源

val stream = Files.newInputStream(Paths.get("/some/file.txt"))
stream.buffered().reader().use { reader ->
    println(reader.readText())
}

要求泛型参数的泛型函数的简单格式

//  public final class Gson {
//  ...
//  public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
//  ...

inline fun <reified T : Any> Gson.fromJson(json): T = this.fromJson(json, T::class.java)

使用可能为空的Boolean

val b: Boolean? = ... 
if (b == true) {
    ...
} else {
    // `b` is false or null
}

编码规范

这页包含了Kotlin语言当前的编码风格

命名风格

如果存疑虑,默认使用java的编码规范,如下:

  • 对变量名使用驼峰法,避免使用下划线
  • 类型名称用大写字母开头
  • 方法名和属性名用小写字母开头
  • 四个空格缩进
  • 公共方法需要有注释记录,这样就会出现在Kotlin文档中

冒号

当用冒号分割类型和父类型时,冒号前后都需要空格;当用冒号分割实体和类型时,冒号后需要空格。

interface Foo<out T : Any> : Bar {
    fun foo(a: Int): T
}

Lambda

在Lambda表达式中,空格用在花括号前后,也用在分割函数体中参数的箭头前后。任何时候,若有可能,lambda表达式都在圆括号的外面。

list.filter { it > 10 }.map { element -> element * 2 }

lambda应当简短避免嵌套,推荐使用it方便的替代明确声明的参数。在嵌套的lambda中使用参数时,参数应当明确申明。

类开头格式

只有少数几个参数的类,可以写在一行:

class Person(id: Int, name: String)

类开头太长时需要格式化,每个主构造函数函数要单独一行且缩进。而且,结束的圆括号也需要单独一行。如果使用继承,调用或列举实现接口的超类构造函数需要在结束圆括号的同一行。

class Person(
    id: Int,
    name: String,
    surname: String
) : Human(id, name) {
    // ...
}

使用多个接口时,超类构造函数放在前面,每个接口放在单独一行。

class Person(
    id: Int,
    name: String,
    surname: String
) : Human(id, name),
    KotlinMaker {
    // ...
}

构造函数参数可以使用单次或多次缩进

Unit

如果函数返回Unit,返回类型可以省略。

fun foo() { 
    // ": Unit"在此处省略
}

函数和属性

在某些场景,使用无参函数和只读属性可交换。尽管在语义上相似,但在文法约定上却有一些偏好。

在下述条件中,比属性比函数更适用:
* 不抛出异常
* 具有O(1)复杂度
* 在初次运行时,更方便计算和缓存
* 每次返回相同值

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值