赞
踩
Java 转 Kotlin 快速入门指南和速查手册
Kotlin 已经是一门成熟的编程语言,它简洁、高效、安全,可与 Java 互操作,出于 Java 而胜于 Java。本文用于向有 Java 基础的人员提供快速的 Kotlin 入门。Kotlin 的优势和详细介绍可参考官方网站。
由于 Kotlin 就是 JetBrains 公司研发的,所以使用他们的 IDE(IntelliJ IDEA) 开发非常简单。
对于新项目直接使用 Kotlin 开发的,在创建项目时选择 Kotlin,选择对应的 JDK 版本即可。如果要在原 Java 项目中添加 Kotlin 进行混合开发,只要在项目中创建一个 Kotlin 类/文件
,在项目中添加一个 .kt
文件,IDE 会自动提示 Kotlin 未配置,点击配置即可。IDE 会在项目配置文件(POM/Gradle)中添加 Kotlin 的依赖和插件,并提供 kotlin.version
的变量,用于指定 Kotlin 的版本。
下面是两者语法和特性的快速指南。
Java
String name = "wwtg99";
final String name = "wwtg99";
Kotlin
var name = "wwtg99" // 可变
val name = "wwtg99" // 不可变
Kotlin 的类型可自动推断,也可显式指定。
var name: String = "wwtg99" // 指定类型为 String
Kotlin 的类型不能为空,如果可能为空,需要加 ?
。
var otherName: String? = null
Kotlin 提供了很多空值判断的简化写法:
Java
if (text != null) {
int length = text.length();
}
Kotlin
// 当 text 不为 null 则执行
text?.let {
val length = text.length
}
// 当 text 不为 null 则获取,不然为 null
val length = text?.length
更多用法请参考空安全。
字符串判断 null 或者空字符串不再需要其他的工具类了。
Kotlin 为字符串提供了很多判断方法。
同时,可通过扩展方法扩展更多的功能,参考扩展。
Kotlin 提供了模版字符串,简化了字符串拼接和格式化的操作。
val str1 = "abc"
val str2 = "123"
val str3 = "${str1}/${str2}" // abc/123
具体详见字符串。
Kotlin 中可以使用 if 表达式或者 ifBlank
方法来设置默认值。
fun main() {
val name = getName().ifBlank { "wwtg99" }
println(name)
}
fun getName(): String = if (Random.nextBoolean()) "" else "wwtg99"
Kotlin 的字符串操作也非常简单。
val str = "Java to Kotlin"
printlin(str[0]) // J
println(str.substring(8..13)) // Kotlin, 前面包含,后面不包含
在 Kotlin 中使用 Regex
类来简化正则表达式的操作。
val regex = Regex("""\w*\d+\w*""")
val input = "login: Pokemon5, password: 1q2w3e4r5t"
val replacementResult = regex.replace(input, replacement = "xxx")
println("Initial input: '$input'")
println("Anonymized input: '$replacementResult'")
Kotlin 中使用 is
进行类型判断。
Java
if (object instanceof Car) {
Car car = (Car) object;
}
Kotlin
if (object is Car) {
var car = object as Car // kotlin 支持自动类型转换,不需要显式转换,详见类型转换
}
// 安全的类型转换,不成功则返回 null
var car = object as? Car
可参考安全的类型转换。
Java
System.out.print("wwtg99");
System.out.println("wwtg99");
Kotlin
print("wwtg99") // 不换行
println("wwtg99") // 换行
if 在 Kotlin 中可以是表达式:
val max = if (a > b) a else b
这就替代了三元操作符,所以 Kotlin 中没有三元操作符 条件 ? 然后 : 否则
。
if 表达式也可以是代码块,最后的表达式就是返回值。
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
同时 Kotlin 还提供了类似 switch
的多分支判断表达式 when
,详见控制流程。
for (i in 1..10) { }
for (i in 1 until 10) { }
for (i in 10 downTo 0) { }
for (i in 1..10 step 2) { }
for (i in 10 downTo 0 step 2) { }
for (item in collection) { }
for ((key, value) in map) { }
详见控制流程。
Kotlin 中的集合分为了可变集合和不可变集合。
List, Set, Map 都是不可变的,而 MutableList, MutableSet, MutableMap 是对应的可变集合。
可以通过 listOf(1, 2, 3)
,mutableListOf(1, 2, 3)
等方法创建。
Kotlin 使用 fun
定义方法。
fun doSomething() {
// logic here
}
带返回类型的方法
fun doSomething(): Int {
// logic here
return 1
}
单表达式函数
fun double(x: Int): Int = x * 2
详细可参考函数。
Kotlin 支持方法参数的默认值,不需要额外重载方法。
fun calculateCost(quantity: Int, pricePerItem: Double = 20.5) = quantity * pricePerItem
calculateCost(10, 25.0) // 250
calculateCost(10) // 205
Kotlin 使用 varargs
定义可变数量的参数。
fun doSomething(vararg numbers: Int) {
// logic here
}
详细可参考可变参数。
Kotlin 中类有一个主构造函数和若干次构造函数。主构造函数在类头中声明,它跟在类名与可选的类型参数后。
class Person constructor(firstName: String) { /*……*/ }
如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
class Person(firstName: String) { /*……*/ }
类也可以声明前缀有 constructor 的次构造函数,使用 this
委托到另一个构造函数。
class Person(val name: String) {
val children: MutableList<Person> = mutableListOf()
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
注:Kotlin 中创建对象不需要 new。
在类中使用 var
或 val
声明属性。会自动添加 getter 和 setter(val 无 setter),直接用属性名使用。
class Address {
var name: String = "wwtg99"
var street: String = "street"
}
fun copyAddress(address: Address): Address {
val result = Address()
result.name = address.name // 将调用访问器
result.street = address.street // 设置属性
return result
}
详细可参考Getter 与 Setter。
Kotlin 提供了四个可见性修饰符:private、 protected、 internal 和 public,默认是 public。
简单来说,public 就是都可以访问,internal 是同模块都可以访问,protected 是内部及子类可访问,private 仅内部可访问。具体可参见可见性修饰符。
Kotlin 提供了数据类,用于 POJO(简单 Java 对象)或仅保存数据的类,类似于 Lombok 的 @Data
注解。
data class User(val name: String, val age: Int)
数据类自动生成以下几个方法:
数据类还有一些能力和约束条件,详见数据类。
在类中可以提供初始化代码块,初始化块按照它们出现在类体中的顺序执行。
class InitOrderDemo(name: String) {
val firstProperty = "第一个属性: $name".also(::println)
init {
println("第一个初始化代码块打印 $name")
}
val secondProperty = "第二个属性: ${name.length}".also(::println)
init {
println("第二个初始化代码块打印 ${name.length}")
}
}
Kotlin 中默认的类都是 final 的,不允许继承,要继承需要添加 open
修饰符。
open class Shape {
open fun draw() { /*……*/ }
}
子类使用冒号 :
继承,覆盖的方法前加 override
。属性覆盖也类似。
class Circle() : Shape() {
override fun draw() { /*……*/ }
}
详细可参考继承。
Kotlin 使用 object
可以声明一个单例对象。
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
Kotlin 使用伴生对象来提供静态方法和变量,使用 companion object
声明。
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
注:伴生对象在运行时仍然是真实的实例成员,在 JVM 平台,如果使用 @JvmStatic 注解的方法或使用 @JvmField 注解或 const 关键词的属性,可以将伴生对象的成员生成为真正的静态方法和属性。
Kotlin 需要获取 Java 的类(Class)对象可以通过以下方式:
// 1. 在类上调用 ::class.java, 其中 ::class 是 Kotlin 的类
val myClass1 = MyClass::class.java
// 2. 在实例上调用 javaClass
val myClass2 = myInstance.javaClass
Kotlin 的 var 属性会生成 Java 的 Getter/Setter,val 只有 Getter。
Kotlin 的包级函数、扩展函数等,会生成一个特殊的 Java 类中的静态方法。例如,在 org.example
包内的 app.kt
文件中声明的所有的函数和属性,包括扩展函数,都编译成一个名为 org.example.AppKt
的 Java 类的静态方法。
可以使用 @JvmName
注解自定义生成的 Java 类的类名。
@file:JvmName("DemoUtils")
package org.example
class Util
fun getTime() { /*……*/ }
在 Java 中
new org.example.Util();
org.example.DemoUtils.getTime();
一个有默认实参值的 Kotlin 函数,在 Java 中只会有一个所有参数都存在的完整参数签名的方法。如果希望向 Java 调用者暴露多个重载,可以使用 @JvmOverloads
注解。该注解也适用于构造函数、静态方法等。但它不能用于抽象方法,包括在接口中定义的方法。对于每一个有默认值的参数,都会生成一个额外的重载,这个重载会把这个参数和它右边的所有参数都移除掉。
class Circle @JvmOverloads constructor(centerX: Int, centerY: Int, radius: Double = 1.0) {
@JvmOverloads fun draw(label: String, lineWidth: Int = 1, color: String = "red") { /*……*/ }
}
会生成如下方法
// 构造函数:
Circle(int centerX, int centerY, double radius)
Circle(int centerX, int centerY)
// 方法
void draw(String label, int lineWidth, String color) { }
void draw(String label, int lineWidth) { }
void draw(String label) { }
Kotlin 没有受检异常,Kotlin 函数的 Java 签名不会声明抛出异常,要声明这个异常,需要添加 @Throws
注解。
@Throws(IOException::class)
fun writeToFile() {
/*……*/
throw IOException()
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。