理解一门语言的最好方式,是用它写代码。不是读关于它的文章,不是看网络讲座,不是把文章收藏进"待读"清单(我们都知道那些文章最后去哪了)。
打开 IDE,写点真正能跑起来的东西。
这篇教程就是为此而写的。我们会从零出发,完成第一个可运行的迷你应用。如果你懂 Java,进度会更快——我会全程做对比。
运行 Kotlin:两种方式,其中一种零分钟上手
直接在浏览器里。打开 play.kotlinlang.org,直接开写。不用安装,不用配置,不用钻进"为什么环境搭不起来"的技术论坛死胡同。最适合第一次接触。
在 IntelliJ IDEA 里。对 Kotlin 的支持是内置的。新建一个 Kotlin 项目——就这么简单。不用装插件,没有任何繁琐流程。
你的第一个程序:
fun main() {
println("Hello, Kotlin!")
}Java 里同样的代码是这样的:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, Kotlin!");
}
}两者做的事情完全一样。Kotlin 只是没有 public static void 和包裹类——因为……我们当初为什么需要那些东西?好问题。Java 从来没给出让人信服的答案。
val 和 var:两个需要记住的关键字
在 Kotlin 里,变量用 val 或 var 声明。
val name = "伟伟" // 不可变。相当于 Java 里的 final。
var age = 25 // 可变。
age = 26 // 没问题。
name = "娜娜" // 编译错误。简单原则:凡是不需要改变的值,一律用 val。只有真正需要修改的时候才用 var。这就像提前和自己约定:"这个我不会动。" Kotlin 会确保你信守承诺。
类型不用写——Kotlin 自己推断:
val score = 100 // Kotlin 知道:这是 Int
val name = "伟伟" // 这是 String或者显式写出来,如果你更喜欢这样:
val score: Int = 100
val name: String = "伟伟"Null-safety:Kotlin 如何消灭 NullPointerException
Tony Hoare 在 1965 年发明了 null,后来把它称为自己"价值十亿美元的错误"。听起来像自我批评——但其实是低估了。NullPointerException 给这个行业造成的损失远不止这个数。
在 Java 里,任何变量都可能是 null。编译器沉默。你在运行时才知道。在生产环境里。有时候是在给客户做现场演示的时候——对,这种事真的发生过。
Kotlin 在类型系统层面解决了这个问题:
var name: String = "伟伟"
name = null // 编译错误。立刻报错。在运行前就拦截了。如果一个变量可能是 null,必须用 ? 明确声明:
var name: String? = "伟伟"
name = null // 我们约定好它可以为 null — 现在没问题。那么当我们需要在可能为 null 的东西上调用方法时怎么办?
println(name?.length) // 如果是 null — 返回 null。不会崩。
println(name?.length ?: 0) // 如果是 null — 返回 0。Elvis 运算符。它叫 Elvis 运算符——因为 ?: 看起来像猫王的发型。这不是玩笑,这是官方文档里的正式说明。
函数
Java 里:
public static int add(int a, int b) {
return a + b;
}Kotlin 里:
fun add(a: Int, b: Int): Int {
return a + b
}更简洁的写法——单表达式函数:
fun add(a: Int, b: Int) = a + bKotlin 支持默认参数值。Java 里要为此写好几个重载方法。Kotlin 只需要一个:
fun greet(name: String, greeting: String = "你好") {
println("$greeting,$name!")
}
greet("伟伟") // 你好,伟伟!
greet("娜娜", "嘿") // 嘿,娜娜!字符串模板——直接在字符串里用 $name。Kotlin 自动把变量值替换进去。不用 +,不用拼接——就应该是这样的嘛。
Data class:告别 boilerplate
经典任务:需要一个数据模型——一个有姓名、年龄和邮箱的用户。
在 Java 里,这意味着构造函数、三个 getter、三个 setter、equals()、hashCode()、toString()。或者用 Lombok。或者接受现实,像 2005 年那样手写一切。
在 Kotlin 里:
data class User(val name: String, val age: Int, val email: String)一行。编译器生成其他所有内容,包括 copy():
val weiwei = User("伟伟", 30, "weiwei@example.com")
val olderWeiwei = weiwei.copy(age = 31)
println(weiwei)
// User(name=伟伟, age=30, email=weiwei@example.com)看看 copy()。你创建一个新对象,只改需要改的字段。Java 里通常要为此写一个 Builder。或者直接忍着。
Extension functions:给别人的类加方法
假设你想给 String 类加一个方法。Java 里——写一个带静态方法的工具类,然后到处写 StringUtils.doSomething(myString)。能用,但感觉像打了个补丁。
Kotlin 里——extension functions:
fun String.isValidEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
println("user@example.com".isValidEmail()) // true
println("这不是邮箱".isValidEmail()) // false读起来就像这个类原生就有这个方法。没有继承,没有包装器。就是加了个方法——然后直接用。
整合起来:一个用户验证器
把我们学到的东西合起来,写点真实的代码。
data class User(val name: String, val email: String?)
fun String.isValidEmail() = contains("@") && contains(".")
fun validateUser(user: User): String {
val emailStatus = user.email?.let {
if (it.isValidEmail()) "有效" else "无效"
} ?: "未填写"
return "${user.name}:邮箱$emailStatus"
}
fun main() {
val users = listOf(
User("伟伟", "weiwei@example.com"),
User("娜娜", "nana-not-email"),
User("小明", null)
)
users.forEach { println(validateUser(it)) }
}
输出:
伟伟:邮箱有效
娜娜:邮箱无效
小明:邮箱未填写注意:null 的处理没有用一个 if。?. 和 ?: 运算符优雅地搞定了一切。小明没填邮箱——没有任何 NPE。生活美好。
这只是个开始
这里我们覆盖了基础:变量、null-safety、函数、data class、extension functions。
后面还有更有趣的内容。协程——无痛的异步代码。Sealed classes——比 switch 更强大的替代方案,不会让你漏掉任何情况。集合的函数式操作——map、filter、reduce 一行搞定。
如果你想系统地学 Kotlin,而不是从散落在各个浏览器标签页的碎片里拼凑——来试试我们的课程吧。62 个关卡,1100 多道题含自动验证,3 个项目可加入作品集。第一关免费。
→ codegym.cc/zh/courses/kotlin
继续阅读
- 什么是 Kotlin,为什么开发者把它加进简历 — 如果你想了解更大的背景:这门语言从哪里来,Google 为什么押注它,以及 Oracle 那段故事。
- Java vs Kotlin:诚实的比较 — 现在你已经看过两种语法,来看详细的对比:null-safety、data class、协程、互操作性。
GO TO FULL VERSION