本文面向有 Java 基础的开发者,快速掌握 Kotlin 与 Java 的核心差异。
Java 中我们需要声明变量的类型:
String name = "Api-X";
final String APP_NAME = "Api-X";Kotlin 使用 val(不可变)和 var(可变):
val name = "Api-X" // 相当于 final String
var count = 0 // 相当于 int (可修改)
var url: String = "" // 显式指定类型项目中的实际用法 (
src/main/kotlin/app/LastRequestPrefs.kt:10-12):
companion object {
private fun prefsFile(): File = File(configHome(), "lastRequest.txt")
fun load(): String = prefsFile().takeIf { it.exists() }?.readText() ?: ""
}Kotlin 编译器会根据右侧表达式自动推断类型:
val repository = CollectionRepository(path) // 自动推断为 CollectionRepository
val url = "https://api.example.com" // 自动推断为 String
val expandedIds = mutableSetOf<String>() // 自动推断为 MutableSet<String>项目中的典型用法 (src/main/kotlin/app/Main.kt:120-130):
var method by remember { mutableStateOf("GET") }
var url by remember { mutableStateOf("https://httpbin.org/get") }
var headersText by remember {
mutableStateOf("Content-Type: application/x-www-form-urlencoded")
}Java 需要手动编写 getter/setter/equals/hashCode:
public class Request {
private String id;
private String url;
private String method;
// 还要手动写 getters, setters, equals, hashCode...
}Kotlin 一行搞定:
data class Request(
val id: String,
val url: String,
val method: String = "GET"
)自动生成:equals(), hashCode(), toString(), copy(), componentN()
项目中的数据模型 (
src/main/kotlin/tree/CollectionModels.kt):
data class Request(
val id: String,
val collectionId: String,
val folderId: String?,
val name: String,
val url: String = "",
val method: String = "GET",
val headersText: String = "",
val bodyText: String = "",
val paramsText: String = "",
val auth: PostmanAuth? = null,
)从 data class 中快速提取字段:
val request = Request("1", "https://api.com", "GET")
val (id, url, method) = request // 解构项目中的实际用法 (src/main/kotlin/app/Main.kt:201-208):
fun addFolderAt(at: TreeSelection) {
val target = repository.newFolderTarget(at) ?: return
val (cid, pid) = target // 解构获取 collectionId 和 parentId
repository.createFolder(cid, pid, "新文件夹").let { fid ->
refreshTree()
expandedCollectionIds = expandedCollectionIds + cid
if (pid != null) expandedFolderIds = expandedFolderIds + pid
}
}为现有类添加新方法,无需继承:
// 扩展函数
fun String.toUri(): URI = URI(this)
// 扩展属性
val String.uri: URI get() = URI(this)项目中的实用扩展 (
src/main/kotlin/http/RequestUrl.kt):
fun String.ensureDefaultHttpScheme(): String {
if (contains("://")) return this
return "https://$this"
}
fun String.extractUrlAndParams(): Pair<String, String> {
val q = indexOf('?')
return if (q > 0) {
Pair(substring(0, q), substring(q + 1))
} else {
Pair(this, "")
}
}Java 匿名内部类 vs Kotlin lambda:
// Java
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
doSomething();
}
});// Kotlin
button.onClick { doSomething() }
// 带参数
list.forEach { item -> println(item.name) }项目中的 lambda 用法 (
src/main/kotlin/app/Main.kt:224-228):
fun mruRequestIdsForSwitcher(): List<String> {
val ordered = RecentRequestUsageStore.orderedIdsNewestFirst { repository.getRequest(it) != null }
val cur = editorRequestId ?: return ordered
val without = ordered.filter { it != cur }
return (listOf(cur) + without).distinct().take(30)
}Kotlin 把空指针安全作为语言特性:
val name: String = "Api-X" // 非空,不能赋 null
val nameNullable: String? = null // 可空
// 安全调用
val len = nameNullable?.length // 如果为 null,返回 null
// Elvis 操作符
val len = nameNullable?.length ?: 0 // null 时提供默认值
// 非空断言(慎用)
val len = nameNullable!!.length // 如果为 null 抛异常项目中的空安全实践 (
src/main/kotlin/db/CollectionRepository.kt):
fun getRequest(id: String): Request? {
return selectRequestByIdStmt.queryForObject(id)?.let {
it.toRequest()
}
}
// 使用处
val r = repository.getRequest(reqId) ?: return
val savedId = LastRequestPrefs.load()
if (savedId.isNotEmpty() && repository.getRequest(savedId) != null) {
// ...
}接收或返回函数的函数:
// 接收函数参数
inline fun <T> lazy(t: () -> T): T = t()
// 返回函数
fun createHandler(action: () -> Unit): () -> Unit = action项目中的高阶函数 (
src/main/kotlin/http/JsonSyntaxHighlight.kt):
fun highlightJson(code: String): List<AnnotatedString> {
// 利用正则 + lambda 处理匹配
val patterns = listOf(
PatternItem(Regex("\"[^\"]+\"(?=\\s*:)"), ColorKey.String),
// ...
)
return buildAnnotatedString { ... }
}单例和伴生对象:
// 单例(项目中的应用设置存储)
object AppSettingsStore {
private var cache: AppSettings? = null
fun snapshot() = cache ?: load().also { cache = it }
// ...
}
// 伴生对象(静态成员)
class MyClass {
companion object {
const val VERSION = "1.0"
}
}项目中的实际应用 (
src/main/kotlin/app/EnvironmentStore.kt):
object EnvironmentStore {
private var cache: EnvironmentsState? = null
fun snapshot(): EnvironmentsState = cache ?: load().also { cache = it }
fun replace(newState: EnvironmentsState) {
cache = newState
save(newState)
}
}| Java | Kotlin |
|---|---|
String s = "hi" |
val s = "hi" |
final String |
val |
String |
var / val + 类型推断 |
| getter/setter/equals | data class |
| 匿名内部类 | lambda |
@Nullable |
String? + ?. |
| static | companion object / object |
本篇介绍了 Kotlin 最核心的语法特性,下一篇我们开始学习 Compose Desktop 环境搭建。