作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
加布里埃尔·吉琴科的头像

Gabriel Gircenko

Gabriel是一名高级Android工程师,拥有8年用Kotlin和Java从头开始构建应用程序的经验, 并促进两种语言之间的转换. 加布里埃尔曾开发过价值数百万美元的应用程序,并在HBO和雅虎等公司拥有行业经验.

Previous Role

高级Android工程师

工作经验

9

Previously At

HBO
Share

的确,Java在Android大战中败给了 Kotlin这是谷歌目前的首选语言,因此更适合新的移动应用程序. 但是Kotlin和Java都提供了许多作为通用语言的优势, 对于开发人员来说,理解语言差异是很重要的, 用于从Java迁移到Kotlin等目的. In this article, 我们将分解Kotlin和Java的异同,以便您可以做出明智的决定,并在两者之间无缝切换.

Kotlin和Java相似吗?

实际上,从高级的角度来看,这两种语言有很多共同之处. Kotlin和Java都运行在 Java虚拟机(JVM) 而不是直接构建到本机代码. 这两种语言可以很容易地相互调用:您可以从Kotlin调用Java代码,也可以从Java调用Kotlin代码. Java 可用于服务器端应用程序,数据库,web前端应用程序, embedded systems 企业应用程序、移动应用程序等等. Kotlin同样是通用的:它针对JVM、Android、JavaScript和java Kotlin/Native,也可用于服务器端、web和桌面开发.

Java是一种比Kotlin成熟得多的语言,它在1996年发布了第一个版本. Though Kotlin 1.在2016年,Kotlin很快成为了官方首选语言 安卓开发 in 2019. 然而,在Android之外,没有人建议用Kotlin代替Java.

Year
Java
Kotlin
1995–2006
JDK Beta, JDK 1.0, JDK 1.1, J2SE 1.2, J2SE 1.3, J2SE 1.4, J2SE 5.0, Java SE 6
N/A
2007
项目织机首次提交
N/A
2010
N/A
Kotlin开发开始了
2011
Java SE 7
Kotlin项目宣布
2012
N/A
Kotlin开源
2014
Java SE 8 (LTS)
N/A
2016
N/A
Kotlin 1.0
2017
Java SE 9
Kotlin 1.2; Kotlin support for Android announced
2018
Java SE 10、Java SE 11 (LTS)
Kotlin 1.3 (coroutines)
2019
Java SE 12, Java SE 13
Kotlin 1.4 (interoperability for Objective-C and Swift); Kotlin announced as Google’s preferred language for developers
2020
Java SE 14, Java SE 15
N/A
2021
Java SE 16、Java SE 17 (LTS)
Kotlin 1.5, Kotlin 1.6
2022
Java SE 18, JDK 19
Kotlin 1.7 (Kotlin K2编译器的alpha版本),Kotlin 1.8
2023
Java SE 20, Java SE 21, JDK 20, JDK 21
Kotlin 1.9
2024
Java SE 22 (scheduled)
Kotlin 2.0 (potentially)

Kotlin vs. Java:性能和内存

在详细介绍Kotlin和Java的特性之前, 我们将检查它们的性能和内存消耗,因为这些因素通常是开发人员和客户的重要考虑因素.

Kotlin, Java, 以及其他JVM语言, 虽然不相等, 在性能方面是否相当相似, 至少与GCC或Clang等其他编译器家族的语言相比是这样. JVM最初是在20世纪90年代针对资源有限的嵌入式系统设计的. 相关的环境要求导致了两个主要的限制:

  • 简单JVM字节码: 当前版本的JVM (Kotlin和Java都在其中编译)只有205条指令. In comparison, 现代x64处理器可以轻松支持超过6个,000编码指令, 取决于计数方法.
  • 运行时(相对于编译时)操作: 多平台方法(写一次就可以在任何地方运行)鼓励运行时(而不是编译时)优化. 换句话说,JVM在运行时将其字节码的大部分转换为指令. However, 提高性能, 您可以使用JVM的开源实现, such as HotSpot, 哪种预编译字节码通过解释器运行得更快.

具有类似的编译过程和运行时环境, Kotlin和Java的性能差异很小,这是因为它们的特性不同. For example:

  • Kotlin的内联函数避免了函数调用,提高性能, 而Java调用额外的开销内存.
  • Kotlin的高阶函数避免了Java lambda的特殊调用 InvokeDynamic,提高性能.
  • Kotlin生成的字节码包含在使用外部依赖项时进行null检查的断言, 与Java相比,性能变慢.

现在让我们转向记忆. 在理论上,对基类型(i.e.(Kotlin的实现)需要比原始数据类型(如Kotlin)更多的分配.e., Java的实现). 然而,在实践中,Java的字节码使用 自动装箱和拆箱 调用来处理对象,如果过多使用,可能会增加计算开销. For example, Java’s String.format method 只接受对象作为输入,因此格式化Java int will box it in an Integer 对象之前调用 String.format.

总的来说,Java和Kotlin在性能和内存方面没有明显的差异. You may examine online benchmarks 哪些在微基准测试中显示了微小的差异, 但这些不能推广到一个完整的生产应用程序的规模.

独特特性比较

Kotlin和Java有核心的相似之处,但是每种语言都提供了不同的、独特的特性. 自从Kotlin成为谷歌Android开发的首选语言, 我发现扩展函数和显式空性是最有用的特性. 另一方面,在使用Kotlin时,我最想念的Java特性是 protected 关键字和三元运算符.

从左到右显示一个白色的可变椭圆, an equals sign, 一个绿色的第一个表情框, a question mark, 一个深蓝色的Second Expression盒子, a colon, 还有一个浅蓝色的第三表情盒. 第一个表达式框有两个箭头:一个标记为“是真的”指向第二个表达式框, 第二个标记为“Is False”的则指向第三个表达式框. 第二个表达式和第三个表达式都有自己的返回值箭头指向变量椭圆.
三元运算符

让我们更详细地分析一下Kotlin和Java中可用的特性. 您可以跟随我的示例,使用Kotlin Playground或Java编译器来获得更实际的学习方法.

Feature
Kotlin
Java
Description
扩展函数
Yes
No
允许您扩展类或接口的新功能,如添加属性或方法,而无需创建新类:

class Example {}

//扩展函数声明
fun Example.printHelloWorld() {println("你好,世界!") }

//扩展函数用法
Example().printHelloWorld()
Smart casts
Yes
No
跟踪内部情况 if 语句,安全自动强制转换:
有趣的例子(a: Any) {
  if (a is String) {
    println(a.length) //自动转换为String
  }
}

Kotlin还提供了安全和不安全的强制转换操作符:
//不安全的"as"强制转换会抛出异常
val a: String = b as String
// safe "as?" Cast失败时返回null
val c: String? = d as? String
Inline functions
Yes
No
通过内联函数代码(将其复制到调用站点)减少内存开销并提高速度: Inline fun示例().
对委托的本地支持
Yes
No
Supports the 委托设计模式 原生地使用the by keyword: 类Derived(b: Base): Base by b.
Type aliases
Yes
No
为现有类型提供缩短或自定义名称, 包括函数和内部类或嵌套类的: typealias ShortName = LongNameExistingType.
私人领域
No
Yes
Offers protected 和默认(也称为 package-private)修饰语,除了 public and private modifiers. Java has all four access modifiers而Kotlin则失踪了 protected 和默认修饰符.
Ternary operator
No
Yes
用更简单、更易读的代码替换if/else语句:

if (firstExpression) {// if/else
  变量= secondexexpression;
} else {
  变量= thirdexexpression;
}

//三元运算符
变量= (firstExpression) ? seconexpression: thirexpression;
隐式扩展转换
No
Yes
允许从较小的数据类型自动转换为较大的数据类型:

int i = 10;
long l = i; // first widening conversion: int to long
float f = l; // second widening conversion: long to float
已检查的异常
No
Yes
类中捕获异常的方法 throws 关键字或用try-catch块处理异常.

注意:受控异常旨在鼓励开发人员设计健壮的软件. However, 他们可以创建样板代码, 使重构变得困难, 并导致错误处理不当. 这个特性是有利还是不利取决于开发人员的偏好.

有一个主题我故意从这个表中排除:Kotlin与Java的空安全性. 这个主题需要对Kotlin和Java进行更详细的比较.

Kotlin vs. Java: Null Safety

在我看来,非空性是Kotlin最伟大的特性之一. 此功能节省了时间,因为开发人员不必处理 NullPointerExceptions (which are RuntimeExceptions).

在Java中,默认情况下,您可以分配 null 为任意变量赋值:

String x = null;
//运行此代码会抛出NullPointerException
try {
    System.out.println("第一个字符:" + x.charAt(0));
} catch (NullPointerException) {
    System.out.println(“抛出NullPointerException!");
}

另一方面,在Kotlin中,我们有两个选择,使变量为空或非为空:

var nonnullablennumber: Int = 1

//这一行抛出编译时错误,因为你不能赋空值
nonnullablennumber = null

var nullablennumber: Int? = 2

//这一行不会抛出错误,因为我们使用了一个可空变量
nullablennumber = null

默认情况下,我使用非空变量, and minimize the use of nullable variables for best practices; these Kotlin versus Java examples are meant to demonstrate differences in the languages. Kotlin初学者应该避免毫无目的地将变量设置为可空的陷阱(在将Java代码转换为Kotlin时也可能发生这种情况)。.

然而,在Kotlin中有一些情况下你会使用可空变量:

Scenario
Example
您正在搜索列表中不存在的项(通常在处理数据层时).
val list: List = listOf(1,2,3)
val searchResultItem = list.firstOrNull{它== 0}
searchResultItem?.let { 
  //找到项目,执行操作 
} ?: run { 
  //没有找到项目,做点什么
}
您希望在运行时初始化变量,使用 lateinit.
lateinit var text:字符串

fun runtimeFunction() {//.g.Android的onCreate
  text = "第一个文本集"
  //在此之后,可以使用该变量
}

我对过度使用感到内疚 lateinit 变量,当我刚开始使用Kotlin时. 最后,我几乎完全不再使用它们了,除了定义的时候 view bindings and 变量注射 in Android:

@Inject //在Hilt库中,这是自动初始化的
lateinit var manager: SomeManager

lateinit var viewBinding: viewBinding

fun onCreate() {// i.e.Android的onCreate

  binding = ActivityMainBinding.膨胀(layoutInflater, parentView, true)
  // ...
}

On the whole, 与Java相比,Kotlin中的null安全性提供了额外的灵活性和改进的开发人员体验.

共享特性差异:在Java和Kotlin之间移动

每种语言都有其独特的特点, Kotlin和Java也共享许多特性, 为了在两种语言之间进行转换,有必要了解它们的特点. 让我们来看看在Kotlin和Java中不同操作的四个常见概念:

Feature
Java
Kotlin
数据传输对象(dto)
Java记录,它保存有关数据或状态的信息,并包括 toString, equals, and hashCode 自Java SE 15以来,默认情况下已可用:

档案雇员(
    int id,
    String firstName,
    String lastName
)
Kotlin数据类的功能类似于Java记录,使用 toString, equals, and copy 方法:

数据类Employee(
    val id: Int,
    val firstName:字符串,
    val lastName:字符串
)
Lambda表达式
Java lambda表达式(从Java 8开始可用)遵循一个简单的 parameter -> expression 语法,多个参数使用圆括号: (parameter1, parameter2) -> { code }:

ArrayList ints =
  new ArrayList<>();
ints.add(5);
ints.add(9);
ints.forEach( (i) ->
  { System.out.println(i); } );
Kotlin lambda表达式遵循该语法 { parameter1, parameter2 -> code } 并且总是被花括号包围:

var p: List =
    自然(“firstPhrase”、“secondPhrase”)
  val isshort = {s1:字符串;
    s2: String -> s1.length < s2.length }
  println (isShorter (p.first(), p.last()))
Java线程使并发成为可能 java.util.concurrency 包允许通过它的实用程序类实现简单的多线程. The Executor and ExecutorService classes 特别有利于并发吗. (Project Loom 还提供轻量级线程.)
Kotlin coroutines, from the kotlinx.coroutines 库,促进并发性,并为多线程包含一个单独的库分支. The memory manager in Kotlin 1.7.20及以后的版本减少了以前对开发者在iOS和Android之间迁移的并发性和多线程的限制.
类中的静态行为
Java静态成员促进了类实例之间的代码共享,并确保只创建一个项目的单一副本. The static 关键字可以应用于变量、函数、块等:

class Example {
    静态void f() {/*...*/}
}
Kotlin companion objects 在类中提供静态行为,但语法不那么简单:

class Example {
    伴侣对象{
        fun f() {/*...*/}
    }
}

当然,Kotlin和Java也有不同的语法. 讨论每个语法差异超出了我们的范围, 但是考虑循环应该会让你对整体情况有一个概念:

Loop Type
Java
Kotlin
for, using in
for (int i=0; i<=5; i++) {
    System.out.Println(“打印6次”);
}
for (i in 0..5) {
    Println(“打印6次”)
}
for, using until
for (int i=0; i<5; i++) {
  System.out.Println(“打印5次”);
}
For (i in 0 until 5) {
  Println(“打印5次”)
}
forEach
List list = Arrays.asList(“第一”、“第二”);

for(字符串值:list) {
  System.out.println(value);
}
var list: List =
  自然(“第一”、“第二”)

list.forEach {
  println(it)
}
while
int i = 5;
while (i > 0) {
  System.out.Println(“打印5次”);
  i--;
}
var i = 5
while (i > 0) {
  Println(“打印5次”)
  i--
}

An 深入了解Kotlin的特性 将有助于Kotlin和Java之间的转换.

Android项目规划:附加考虑

我们研究了在通用上下文中选择Kotlin还是Java时需要考虑的许多重要因素. However, 如果不解决房间里的大象:Android,那么Kotlin与Java的对比分析是不完整的. Are you making an Android应用程序从头开始 想知道你应该用Java还是Kotlin? 毫无疑问,选择Kotlin,谷歌首选的Android语言.

然而,这个问题对于现有的Android应用程序来说是没有意义的. 根据我和很多客户打交道的经验, 还有两个更重要的问题是:你们如何对待科技债务? 你如何照顾你的开发人员的经验(DX)?

那么,你们是如何处理科技债务的呢? 如果你的Android应用在2023年使用Java, 你的公司可能在推动新功能,而不是处理技术债务. 这是可以理解的. 市场竞争激烈,需要快速的应用更新周期. 但技术债务有一个隐藏的影响:每次更新都会导致成本增加,因为工程师必须处理不稳定的代码,而这些代码很难重构. 公司很容易进入一个永无止境的循环 技术债务和成本. 或许值得暂停一下,投资于长期解决方案, 即使这意味着大规模的代码重构或更新你的代码库以使用像Kotlin这样的现代语言.

你如何通过DX照顾你的开发人员? 开发人员在其职业生涯的各个层面都需要支持:

  • 初级开发人员可以从适当的资源中获益.
  • 中级开发人员通过领导和教学的机会成长.
  • 高级开发人员需要架构和实现优美代码的能力.

高级开发人员对DX的关注尤其重要,因为他们的专业知识会影响到所有工程师. 高级开发人员喜欢学习和试验最新的技术. 跟上最新的趋势和语言版本将使您的团队成员发挥最大的潜力. 无论团队选择何种语言,这一点都很重要, 尽管不同的语言有不同的时间表:对于像Kotlin这样的年轻语言, an engineer working on legacy code can fall behind trends in less than one year; with mature languages like Java, 会花更长的时间.

Kotlin和Java:两种强大的语言

而Java有广泛的应用, 不可否认,Kotlin已经抢了它的风头,成为开发新Android应用程序的首选语言. Google把所有的精力都投入到了Kotlin上,它的新技术是Kotlin优先的. 现有应用程序的开发人员可以考虑将Kotlin集成到任何新代码中——intellij附带了一个自动的 Java转Kotlin工具并且应该研究超出我们最初的语言选择问题的因素.


Toptal工程博客的编辑团队向 Thomas Wuillemin 查看本文中提供的代码示例和其他技术内容.

了解基本知识

  • Kotlin可以与Java一起使用吗?

    是的,您可以从Kotlin调用Java代码,也可以从Java调用Kotlin代码.

  • Java和Kotlin是一样的吗?

    Java和Kotlin是两种独立的语言. 尽管它们有某些相似之处,例如它们的典型用例(例如.g.(Android开发),它们有不同的功能和语法.

  • Kotlin正在取代Java吗?

    Kotlin是Google首选的Android开发语言,但许多Android应用程序仍然使用Java. 新的Android应用当然应该使用Kotlin, 但对于使用Java的现有Android应用程序来说,选择变得更加复杂.

  • 为什么我应该使用Kotlin而不是Java?

    在新的Android应用程序中使用Kotlin而不是Java是有意义的,因为谷歌的最新技术是Kotlin优先的, Kotlin有许多吸引人的特点, a large community, 以及大量的文档.

  • Kotlin比Java简单吗?

    Kotlin和Java都是相对初学者友好的,有强大的社区和文档. In particular, Kotlin简洁的语法和特性的好处, 例如非空性, 使其比Java更容易学习.

就这一主题咨询作者或专家.
Schedule a call
加布里埃尔·吉琴科的头像
Gabriel Gircenko

Located in Zagreb, Croatia

Member since November 10, 2016

About the author

Gabriel是一名高级Android工程师,拥有8年用Kotlin和Java从头开始构建应用程序的经验, 并促进两种语言之间的转换. 加布里埃尔曾开发过价值数百万美元的应用程序,并在HBO和雅虎等公司拥有行业经验.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Previous Role

高级Android工程师

工作经验

9

Previously At

HBO

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.