使用 Kotlin 開發(fā)幾個月后,我后悔了!團隊決定回歸 Java
作者:Bartosz Walacik
鏈接:https://allegro.tech/2018/05/From-Java-to-Kotlin-and-Back-Again.html
譯者:安翔
毫無疑問,Kotlin 目前很受歡迎,業(yè)界甚至有人認為其將取代 Java 的霸主地位。它提供了 Null 安全性,從這一點來說它確實比 Java 更好。那么是不是這就意味著開發(fā)者應該毫不猶豫地擁抱 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。我是新來的,我可以使用靜態(tài)成員嗎?"他問。 ?“不行。我是面向?qū)ο蟮模o態(tài)成員不是面向?qū)ο蟮摹!?Kotlin 回答。 ?“好吧,但我需要 MyClass 的 logger,我該怎么辦?”? “這個沒問題,使用伴生對象即可。” ?“那是什么東西?” “這是局限到你的類的單獨對象。把你的 logger 放在伴生對象中。”Kotlin解釋說。 ?“我懂了。這樣對嗎?”
class?MyClass?{
????companion?object?{
????????val?logger?=?LoggerFactory.getLogger(MyClass::class.java)
????}
}
“正確!” ?“很詳細的語法,”程序員看起來很疑惑,“但是沒關系,現(xiàn)在我可以像 MyClass.logger 這樣調(diào)用我的 logger,就像 Java 中的一個靜態(tài)成員?”? “嗯......是的,但它不是靜態(tài)成員!這里只有對象。把它看作是已經(jīng)實例化為單例的匿名內(nèi)部類。事實上,這個類并不是匿名的,它的名字是 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"
????}
}
以上內(nèi)容編譯自 From Java to Kotlin and Back Again,作者 Kotlin ketckup。 他是一名具有15年以上專業(yè)經(jīng)驗的軟件工程師,專注于JVM 。在 Allegro,他是一名開發(fā)團隊負責人,JaVers 項目負責人,Spock 倡導者。此外,他還是 allegro.tech/blog 的主編。
有時候你必須使用靜態(tài)。舊版本 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 原則的情況下,沒有辦法產(chǎn)生正確的基于價值的數(shù)據(jù)。 這就是為什么 Kotlin 不允許數(shù)據(jù)類繼承的原因。
評論
圖片
表情
