阅读 668

Android:Kotlin详细入门学习指南-基础语法(一)

Android:Kotlin详细入门学习指南-基础语法(一)

本人也是在初学Kotlin,如有错误,请帮忙指出,持续更新

  • Kotlin被Google官方认为是Android开发的一级编程语言
  • 自 2019 年 Google I/O 以来,Kotlin 就成为了 Android 移动开发的首选。
  • 首先来看看Kotlin的基础语法

Kotlin是什么

  • Kotlin是Android开发的一级编程语言(Google官方认证)
  • 由JetBrains公司在2010年推出 & 开源,与Java语言互通 & 具备多种Java尚不支持的新特性
  • Android Studio3.0后的版本支持Kotlin

优点

  • 码更少、可读性更强 - 花更少的时间来编写代码与理解他人的代码
  • 成熟的语言与环境 - 自 2011 年创建以来,Kotlin 不仅通过语言而且通过强大的工具在整个生态系统中不断发展。 现在,它已无缝集成到 Android Studio 中, 并被许多公司积极用于开发 Android 应用程序。
  • Android Jetpack 与其他库中的 Kotlin 支持 - KTX 扩展 为现有的 Android 库添加了 Kotlin 语言特性,如协程、扩展函数、lambdas 与命名参数。
  • 与 Java 的互操作性 - 可以在应用程序中将 Kotlin 与 Java 编程语言一起使用, 而无需将所有代码迁移到 Kotlin。
  • 支持多平台开发 - 不仅可以使用 Kotlin 开发 Android,还可以开发 iOS、后端与 Web 应用程序。 享受在平台之间共享公共代码的好处。
  • 代码安全 - 更少的代码与更好的可读性导致更少的错误。Kotlin 编译器检测这些剩余的错误,从而使代码安全。
  • 易学易用 - Kotlin 非常易于学习,尤其是对于 Java 开发人员而言。
  • 大社区 - Kotlin 得到了社区的大力支持与许多贡献,该社区在全世界范围内都在增长。 根据 Google 的说法,Play 商店前 1000 个应用中有 60% 以上使用 Kotlin。

使用

1、点击Android Studio settings -> Plugins -> 搜索Kotlin Languages插件 2、在根目录的build.gradle中加入

buildscript {
    ext.kotlin_version = '1.3.61'
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
复制代码

3、在app/build.gradle中引入

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

buildscript {
    ext.kotlin_version = '1.3.61'
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
复制代码

基本语法

定义包名 - 在源文件的开头定义包名:包名不必和文件夹路径一致:源文件可以放在任意位置。

package my.demo 
import java.util.
* //...
复制代码

定义函数:定义一个函数接受两个 int 型参数,返回值为 int

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

fun main(args: Array<String>) {
 	print("sum of 3 and 5 is ")
  	println(sum(3, 5)) 
  }
复制代码

该函数只有一个表达式函数体以及一个自推导型的返回值:

fun sum(a: Int, b: Int) = a + b 
fun main(args: Array<String>) {
 	println("sum of 19 and 23 is ${sum(19, 23)}") 
 }
复制代码

返回一个没有意义的值: Unit 的返回类型可以省略

fun printSum(a: Int, b: Int): Unit { 
	println("sum of $a and $b is ${a + b}")
	 }
fun main(args: Array<String>) { 
printSum(-1, 8)
	 }
复制代码

定义局部变量 声明常量:

fun main(args: Array<String>) {
	 val a: Int = 1 // 立即初始化 
	 val b = 2 // 推导出Int型 
	 val c: Int // 当没有初始化值时必须声明类型 
	 c = 3 // 赋值 
	 println("a = $a, b = $b, c = $c")
  }
复制代码

变量:

fun main(args: Array<String>) {
	 var x = 5 // 推导出Int类型 
	 x += 1 println("x = $x")
 }
复制代码

注释: 与 java 和 javaScript 一样,Kotlin 支持单行注释和块注释。

// 单行注释
/* 哈哈哈哈 这是块注释 */
复制代码

与 java 不同的是 Kotlin 的 块注释可以级联。 使用字符串模板

fun main(args: Array<String>) {
	 var a = 1 // 使用变量名作为模板: 
	 val s1 = "a is $a" a = 2 // 使用表达式作为模板:
	 val s2 = "${s1.replace("is", "was")}, but now is $a" println(s2)
 }
复制代码

使用条件表达式

fun maxOf(a: Int, b: Int): Int { 
	if (a > b) {
	 return a 
	 } else { 
	 return b
	  } 
 }
 fun main(args: Array<String>) { 
 	println("max of 0 and 42 is ${maxOf(0, 42)}") 
 }
复制代码

把if当表达式:

fun maxOf(a: Int, b: Int) = if (a > b) a else b
fun main(args: Array<String>) {
	println("max of 0 and 42 is ${maxOf(0, 42)}")
}
复制代码

使用可空变量以及空值检查 当空值可能出现时应该明确指出该引用可空。 下面的函数是当 str 中不包含整数时返回空:

fun parseInt(str : String): Int?{ //... }
复制代码

使用值检查并自动转换 使用 is 操作符检查一个表达式是否是某个类型的实例。如果对不可变的局部变量或 属性进行过了类型检查,就没有必要明确转换:

fun getStringLength(obj: Any): Int? {
 if (obj is String) { 
 // obj 将会在这个分支中自动转换为 String 类型 return obj.length }
 // obj 在种类检查外仍然是 Any 类型 return null
 }
复制代码

使用循环

fun main(args: Array<String>) {
	 val items = listOf("apple", "banana", "kiwi") 
	 for (item in items) {
	  println(item) 
	  }
}
复制代码

或者这样:

fun main(args: Array<String>) { 
	val items = listOf("apple", "banana", "kiwi") 
	for (index in items.indices) {
	 println("item at $index is ${items[index]}") 
	 } 
 }
复制代码

使用 while 循环

fun main(args: Array<String>) { 
	 val items = listOf("apple", "banana", "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" 
	 "Hello" ->"Greeting" 
	  is Long -> "Long" 
	  !is String -> "Not a string" 
	  else -> "Unknown" 
  }
  fun main(args: Array<String>) {
	     println(describe(1)) println(describe("Hello"))
	     println(describe(1000L))
	     println(describe(2)) 
	     println(describe("other"))
 }
复制代码

使用ranges 使用 in 操作符检查数值是否在某个范围内:

fun main(args: Array<String>) { 
	val x = 10 
	val y = 9
	 if (x in 1..y+1) {
	  println("fits in range") 
	  } 
 }
复制代码

检查数值是否在范围外:

if (-1 !in 0..list.lastIndex) { 
	println("-1 is out of range") 
}
复制代码

使用步进

for (x in 1..10 step 2)
for (x in 9 downTo 0 step 3)
复制代码

使用集合

对一个集合进行迭代

fun main(args: Array<String>) { 
	val items = listOf("apple", "banana", "kiwi") 
	for (item in items) {
	 println(item) 
	 } 
 }
复制代码

使用 in 操作符检查集合中是否包含某个对象

fun main(args: Array<String>) { 
	val items = setOf("apple", "banana", "kiwi") 
	when { 
	"orange" in items -> println("juicy") 
	"apple" in items -> println("apple is fine too") 
	} 
}
复制代码

使用lambda表达式过滤和映射集合

fun main(args: Array<String>) { 
	val fruits = listOf("banana", "avocado", "apple", "kiwi") 
	fruits 
	.filter { it.startsWith("a") } 
	.sortedBy { it } 
	.map { it.toUpperCase() } 
	.forEach { println(it) 
} 
复制代码

习惯用语

创建DTOs(POJOs/POCOs) 数据类 相当于java的Bean,

data class Customer(val name: String, val email: String)
复制代码

给 Customer 类提供如下方法 -为所有属性添加 getters ,如果为 var 类型同时添加 setters -- equals() - - haseCode() -- toString() -- copy()

函数默认值

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

过滤 list

val positives = list.filter { x -> x >0 }
复制代码

或者更短:

val positives = list.filter { it > 0 }
复制代码

字符串插值

println("Name $name")
复制代码

实例检查

when (x) { 
	is Foo -> ... 
	is Bar -> ... 
	else -> ... 
}
复制代码

遍历 map/list

for ((k, v) in map) {
	 print("$k -> $v") 
}
复制代码

k,v 可以随便命名 使用 ranges

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) { ... } 
for (i in 1..100) { ... } 
for (i in 2..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
复制代码

懒属性(延迟加载)

val p: String by lazy { // 生成string的值 }
复制代码

扩展函数

fun String.spcaceToCamelCase() { ... } 
"Convert this to camelcase".spcaceToCamelCase()
复制代码

创建单例模式

object Resource {
 	val name = "Name"
}
复制代码

如果不为空则... 的简写

val files = File("Test").listFiles() 
println(files?.size)
复制代码

如果不为空...否则... 的简写

val files = File("test").listFiles() 
println(files?.size ?: "empty")
复制代码

如果声明为空执行某操作

val data = ... 
val email = data["email"] ?: throw IllegalStateException("Email is missing!")
复制代码

如果不为空执行某操作

val date = ... 
data?.let{ ...//如果不为空执行该语句块 }
复制代码

返回 when 判断

fun transform(color: String): Int {
	 return when(color) { 
	 "Red" -> 0 "Green" -> 1 
	 "Blue" -> 2 
	 else -> throw IllegalArgumentException("Invalid color pa ram value")
	  } 
}
复制代码

try-catch 表达式

fun test() {
	 val result = try {
	  count() 
	  }catch (e: ArithmeticException) {
	   throw IllegaStateException(e)
	  }//处理 result
}
复制代码

if 表达式

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

需要泛型信息的泛型函数的方便形式

// 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.fromJs on(json, T::class.java)
复制代码

命名风格

如有疑惑,默认为Java编码约定,比如: 使用骆

  • 驼命名法(在命名中避免下划线)
  • 类型名称首字母大写
  • 方法和属性首字母小写
  • 缩进用四个空格
  • public 方法要写说明文档,这样它就可以出现在 Kotllin Doc 中

冒号

在冒号区分类型和父类型中要有空格,在实例和类型之间是没有空格的:

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

Lambdas

在 Lambdas 表达式中,大括号与表达式间要有空格,箭头与参数和函数体间要有 空格。尽可能的把 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"被省略了 }
复制代码

函数 vs 属性

在某些情况下,没有参数的函数可以与只读属性互换。尽管语义是相似的,但是有 一些风格上的约定在什么时候更偏向于另一个。 在下面的情况下,更偏向于属性而不是一个函数:

  • 不需要抛出异常 -- 拥有O(1)复杂度 -- 低消耗的计算(或首次运行结果会被缓 存) -- 返回与调用相同的结果

本人也是在初学Kotlin,如有错误,请帮忙指出,持续更新

文章分类
Android
文章标签