使用 Kotlin 开发几个月后,我后悔了!团队决定回归 Java
开发者全社区
共 12027字,需浏览 25分钟
·
2020-10-15 00:22
作者:Bartosz Walacik
链接:https://allegro.tech/2018/05/From-Java-to-Kotlin-and-Back-Again.html
译者:安翔
毫无疑问,Kotlin 目前很受欢迎,业界甚至有人认为其将取代 Java 的霸主地位。它提供了 Null 安全性,从这一点来说它确实比 Java 更好。那么是不是这就意味着开发者应该毫不犹豫地拥抱 Kotlin,否则就落伍了?
等等,或许事情并非如此。
在开始使用 Kotlin 编程之前,本文想要分享个故事给你。在这个故事中,作者最早使用 Kotlin 来编写一个项目,后来 Kotlin 的各种怪异模式以及一些其他障碍越来越让人厌烦,最终,他们决定重写这个项目。
fun inc(num : Int) {
val num = 2
if (num > 0) {
val num = 3
}
println ("num: " + num)
}
void inc(int num) {
int num = 2; //error: variable 'num' is already defined in the scope
if (num > 0) {
int num = 3; //error: variable 'num' is already defined in the scope
}
System.out.println ("num: " + num);
}
public class Shadow {
int val;
public Shadow(int val) {
this.val = val;
}
}
var a = "10"
var a : String = "10"
var a = "10";
https://medium.com/@afinlay/java-10-sneak-peek-local-variable-type-inference-var-3022016e1a2b
val a: String? = null // ok
val b: String = null // compilation error
println (a.length) // compilation error
println (a?.length) // fine, prints null
println (a?.length ?: 0) // fine, prints 0
public class Utils {
static String format(String text) {
return text.isEmpty() ? null : text;
}
}
fun doSth(text: String) {
val f: String = Utils.format(text) // compiles but assignment can throw NPE at runtime
println ("f.len : " + f.length)
}
fun doSth(text: String) {
val f: String = Utils.format(text) ?: "" // safe with Elvis
println ("f.len : " + f.length)
}
fun doSth(text: String) {
val f: String? = Utils.format(text) // safe
println ("f.len : " + f.length) // compilation error, fine
println ("f.len : " + f?.length) // null-safe with ? operator
}
fun doSth(text: String) {
val f = Utils.format(text) // f type inferred as String!
println ("f.len : " + f.length) // compiles but can throw NPE at runtime
}
fun doSth(text: String) {
val f = Utils.format(text)!! // throws NPE when format() returns null
println ("f.len : " + f.length)
}
Gson gson = new GsonBuilder().registerTypeAdapter(LocalDate.class, new LocalDateAdapter()).create();
def gson = new GsonBuilder().registerTypeAdapter(LocalDate, new LocalDateAdapter()).create()
val kotlinClass : KClass = LocalDate::class
val javaClass : Class= LocalDate::class.java
val gson = GsonBuilder().registerTypeAdapter(LocalDate::class.java, LocalDateAdapter()).create()
int inc(int i) {
return i + 1;
}
fun inc(i: Int): Int {
return i + 1
}
private fun getMetricValue(kafkaTemplate : KafkaTemplate<String, ByteArray>, metricName : String) : Double {
...
}
@Bean
fun kafkaTemplate(
@Value("\${interactions.kafka.bootstrap-servers-dc1}") bootstrapServersDc1: String,
@Value("\${interactions.kafka.bootstrap-servers-dc2}") bootstrapServersDc2: String,
cloudMetadata: CloudMetadata,
@Value("\${interactions.kafka.batch-size}") batchSize: Int,
@Value("\${interactions.kafka.linger-ms}") lingerMs: Int,
metricRegistry : MetricRegistry
): KafkaTemplate{
val bootstrapServer = if (cloudMetadata.datacenter == "dc1") {
bootstrapServersDc1
}
...
}
MongoExperimentsRepository repository
repository : MongoExperimentsRepository
“嗨,Kotlin。我是新来的,我可以使用静态成员吗?"他问。 “不行。我是面向对象的,静态成员不是面向对象的。” Kotlin 回答。 “好吧,但我需要 MyClass 的 logger,我该怎么办?” “这个没问题,使用伴生对象即可。” “那是什么东西?” “这是局限到你的类的单独对象。把你的 logger 放在伴生对象中。”Kotlin解释说。 “我懂了。这样对吗?”
class MyClass {
companion object {
val logger = LoggerFactory.getLogger(MyClass::class.java)
}
}
“正确!” “很详细的语法,”程序员看起来很疑惑,“但是没关系,现在我可以像 MyClass.logger 这样调用我的 logger,就像 Java 中的一个静态成员?” “嗯......是的,但它不是静态成员!这里只有对象。把它看作是已经实例化为单例的匿名内部类。事实上,这个类并不是匿名的,它的名字是 Companion,但你可以省略这个名字。看到了吗?这很简单。"
class AppRunner {
companion object {
@JvmStatic fun main(args: Array<String>) {
SpringApplication.run(AppRunner::class.java, *args)
}
}
}
import java.util.Arrays;
...
List<String> strings = Arrays.asList("Saab", "Volvo");
import com.google.common.collect.ImmutableMap;
...
Map<String, String> string = ImmutableMap.of("firstName", "John", "lastName", "Doe");
const list = ['Saab', 'Volvo']
const map = {'firstName': 'John', 'lastName' : 'Doe'}
list = ['Saab', 'Volvo']
map = {'firstName': 'John', 'lastName': 'Doe'}
def list = ['Saab', 'Volvo']
def map = ['firstName': 'John', 'lastName': 'Doe']
val list = listOf("Saab", "Volvo")
val map = mapOf("firstName" to "John", "lastName" to "Doe")
public int parseAndInc(String number) {
return Optional.ofNullable(number)
.map(Integer::parseInt)
.map(it -> it + 1)
.orElse(0);
}
fun parseAndInc(number: String?): Int {
return number.let { Integer.parseInt(it) }
.let { it -> it + 1 } ?: 0
}
fun parseAndInc(number: String?): Int {
return number?.let { Integer.parseInt(it) }
?.let { it -> it + 1 } ?: 0
}
data class User(val name: String, val age: Int)
open class Base
class Derived : Base()
buildscript {
dependencies {
classpath group: 'org.jetbrains.kotlin', name: 'kotlin-allopen', version: "$versions.kotlin"
}
}
以上内容编译自 From Java to Kotlin and Back Again,作者 Kotlin ketckup。 他是一名具有15年以上专业经验的软件工程师,专注于JVM 。在 Allegro,他是一名开发团队负责人,JaVers 项目负责人,Spock 倡导者。此外,他还是 allegro.tech/blog 的主编。
有时候你必须使用静态。旧版本 public static void main() 仍然是启动 Java 应用程序的唯一方式。
class AppRunner {
companion object {
@JvmStatic fun main(args: Array<String>) {
SpringApplication.run(AppRunner::class.java, *args)
}
}
}
fun main(args:Array ) { SpringApplication.run(AppRunner :: class.java,* args)}
fun main(args:Array ) { runApplication(* args)}
如果你喜欢 Optional ,你可以使用它。Kotlin 在 JVM 上运行。
这个限制不是 Kotlin 的错。在 equals() 没有违反 Liskov 原则的情况下,没有办法产生正确的基于价值的数据。 这就是为什么 Kotlin 不允许数据类继承的原因。
评论