1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        再見,Kotlin !你好, Java !

        共 17187字,需瀏覽 35分鐘

         ·

        2021-07-20 13:18

        點(diǎn)擊上方“Java技術(shù)江湖”,選擇“設(shè)為星標(biāo)

        回復(fù)”666“獲取全網(wǎng)最熱的Java核心知識點(diǎn)整理



        作者:Bartosz Walacik | 來自:CSDN |  編輯 :可可
        原文:https://allegro.tech/2018/05/From-Java-to-Kotlin-and-Back-Again.html


        毫無疑問,Kotlin 在去年很受歡迎,業(yè)界甚至有人認(rèn)為其將取代 Java 的霸主地位。它提供了 Null 安全性,從這一點(diǎn)來說它確實(shí)比 Java 更好。那么是不是這就意味著開發(fā)者應(yīng)該毫不猶豫地?fù)肀?Kotlin,否則就落伍了?
        等等,或許事情并非如此。
        在開始使用 Kotlin 編程之前,本文想要分享個故事給你。在這個故事中,作者最早使用 Kotlin 來編寫一個項(xiàng)目,后來 Kotlin 的各種怪異模式以及一些其他障礙越來越讓人厭煩,最終,他們決定重寫這個項(xiàng)目。
        以下為譯文:
        一直以來,我對基于 JVM 的語言都非常情有獨(dú)鐘。我通常會用 Java 來編寫主程序,再用 Groovy 編寫測試代碼,兩者配合使用得心應(yīng)手。
        2017年夏天,團(tuán)隊發(fā)起了一個新的微服務(wù)項(xiàng)目,和往常一樣,我們需要對編程語言和技術(shù)進(jìn)行選型。部分團(tuán)隊成員是 Kotlin 的擁護(hù)者,再加上我們都想嘗試一下新的東西,于是我們決定用 Kotlin 來開發(fā)這個項(xiàng)目。由于 Spock 測試框架不支持 Kotlin,因此我們決定堅持使用 Groovy 來測試。
        2018年春天,使用 Kotlin 開發(fā)幾個月之后,我們總結(jié)了 Kotlin 的優(yōu)缺點(diǎn),最終結(jié)論表明 Kotlin 降低了我們的生產(chǎn)力。
        于是我們使用 Java 來重寫這個微服務(wù)項(xiàng)目。
        那么 Kotlin 主要存在哪些弊端?下面來一一解釋。
        名稱遮蔽
        這是 Kotlin 最讓我震驚的地方??纯聪旅孢@個方法:


        fun inc(num : Int) {
            val num = 2
            if (num > 0) {
                val num = 3
            }
            println ("num: " + num)
        }


        當(dāng)你調(diào)用 inc(1) 會輸出什么呢?在 Kotlin 中, 方法的參數(shù)無法修改,因此在本例中你不能改變 num。這個設(shè)計很好,因?yàn)槟悴粦?yīng)該改變方法的輸入?yún)?shù)。但是你可以用相同的名稱定義另一個變量并對其進(jìn)行初始化。
        這樣一來,這個方法作用域中就有兩個名為 num 的變量。當(dāng)然,你一次只能訪問其中一個 num,但是 num 值會被改變。
        在 if 語句中再添加另一個 num,因?yàn)樽饔糜虻脑?num 并不會被修改。
        于是,在 Kotlin 中,inc(1) 會輸出 2。同樣效果的 Java 代碼如下所示,不過無法通過編譯: 


        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);
        }


        名字遮蔽并不是 Kotlin 發(fā)明的,這在編程語言中很常見。在 Java 中我們習(xí)慣用方法參數(shù)來映射類字段:


        public class Shadow {
            int val;
            public Shadow(int val) {
                this.val = val;
            }
        }


        在 Kotlin 中名稱遮蔽有些嚴(yán)重,這是 Kotlin 團(tuán)隊的一個設(shè)計缺陷。
        IDEA 團(tuán)隊試圖通過向每個遮蔽變量顯示警告信息來解決這個問題。兩個團(tuán)隊在同一家公司工作,或許他們可以互相交流并就遮蔽問題達(dá)成共識。我從個人角度贊成 IDEA 的做法因?yàn)槲蚁氩坏接心男?yīng)用場景需要遮蔽方法參數(shù)。
        類型推斷
        在Kotlin中,當(dāng)你聲明一個var或是val,你通常會讓編譯器從右邊的表達(dá)式類型中猜測變量類型。我們稱之為局部變量類型推斷,這對程序員來說是一個很大的改進(jìn)。它允許我們在不影響靜態(tài)類型檢查的情況下簡化代碼。
        例如,這個Kotlin代碼:


        var a = "10"


        Kotlin 編譯器會將其翻譯成: 


        var a : String = "10"


        Java 同樣具備這個特性,Java 10中的類型推斷示例如下:  


        var a = "10";


        實(shí)話實(shí)說,Kotlin 在這一點(diǎn)上確實(shí)更勝一籌。當(dāng)然,類型推斷還可應(yīng)用在多個場景。關(guān)于 Java 10中的局部變量類型推斷,點(diǎn)擊以下鏈接了解更多:
        • https://medium.com/@afinlay/java-10-sneak-peek-local-variable-type-inference-var-3022016e1a2b

        Null 安全類型
        Null 安全類型是 Kotlin 的殺手級功能。
        這個想法很好,在 Kotlin 中,類型默認(rèn)不可為空。如果你需要添加一個可為空的類型,可以像下列代碼這樣: 


        val a: String? = null      // ok
        val b: String = null       // compilation error


        假設(shè)你使用了可為空的變量但是并未進(jìn)行空值檢查,這在 Kotlin 將無法通過編譯,比如:


        println (a.length)          // compilation error
        println (a?.length)         // fine, prints null
        println (a?.length ?: 0)    // fine, prints 0


        那么是不是如果你同時擁有不可為空和可為空的變量,就可以避免 Java 中最常見的 NullPointerException 異常嗎?事實(shí)并沒有想象的簡單。
        當(dāng) Kotlin 代碼必須調(diào)用 Java 代碼時,事情會變得很糟糕,比如庫是用 Java 編寫的,我相信這種情況很常見。于是第三種類型產(chǎn)生了,它被稱為平臺類型。Kotlin 無法表示這種奇怪的類型,它只能從 Java 類型推斷出來。它可能會誤導(dǎo)你,因?yàn)樗鼘罩岛軐捤?,并且會禁?Kotlin 的 NULL 安全機(jī)制。
        看看下面這個 Java 方法:


        public class Utils {
            static String format(String text{
                return text.isEmpty() ? null : text;
            }
        }


        假如你想調(diào)用 format(String)。應(yīng)該使用哪種類型來獲得這個 Java 方法的結(jié)果呢?你有三個選擇。
        第一種方法:你可以使用 String,代碼看起來很安全,但是會拋出 NullPointerException 異常。


        fun doSth(text: String) {
            val f: String = Utils.format(text)       // compiles but assignment can throw NPE at runtime
            println ("f.len : " + f.length)
        }


        那你就需要用 Elvis 來解決這個問題:


        fun doSth(text: String) {
            val f: String = Utils.format(text) ?: ""  // safe with Elvis
            println ("f.len : " + f.length)
        }


        第二種方法:你可以使用 String,能夠保證 Null 安全性。


        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
        }


        第三種方法:讓 Kotlin 做局部變量類型推斷如何? 


        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
        }


        餿主意!這個 Kotlin 代碼看起來很安全、可編譯,但是它容忍了空值,就像在 Java 中一樣。
        除此之外,還有另外一個方法,就是強(qiáng)制將 f 類型推斷為 String:


        fun doSth(text: String) {
            val f = Utils.format(text)!!          // throws NPE when format() returns null
            println ("f.len : " + f.length)
        }


        在我看來,Kotlin 的所有這些類似 scala 的類型系統(tǒng)過于復(fù)雜。Java 互操作性似乎損害了 Kotlin 類型推斷這個重量級功能。
        類名稱字面常量
        使用類似 Log4j 或者 Gson 的 Java 庫時,類文字很常見。
        Java 使用 .class 后綴編寫類名: 


        Gson gson = new GsonBuilder().registerTypeAdapter(LocalDate.class, new LocalDateAdapter()).create();


        Groovy 把類進(jìn)行了進(jìn)一步的簡化。你可以忽略 .class,它是 Groovy 或者 Java 類并不重要。


        def gson = new GsonBuilder().registerTypeAdapter(LocalDate, new LocalDateAdapter()).create()


        Kotlin 把 Kotlin 類和 Java 類進(jìn)行了區(qū)分,并為其提供了語法規(guī)范:


        val kotlinClass : KClass<LocalDate> = LocalDate::class
        val javaClass : Class<LocalDate> = LocalDate::class.java


        因此在 Kotlin 中,你必須寫成如下形式:


        val gson = GsonBuilder().registerTypeAdapter(LocalDate::class.javaLocalDateAdapter()).create()


        這看起來非常丑陋。
        反向類型聲明
        C 系列的編程語言有標(biāo)準(zhǔn)的聲明類型的方法。簡而言之,首先指定一個類型,然后是該符合類型的東西,比如變量、字段、方法等等。
        Java 中的表示方法是:


        int inc(int i) {
            return i + 1;
        }


        Kotlin 中則是:


        fun inc(i: Int)Int {
            return i + 1
        }


        這種方法有幾個原因令人討厭。
        首先,你需要在名稱和類型之間加入這個多余的冒號。這個額外角色的目的是什么?為什么名稱與其類型要分離?我不知道。可悲的是,這讓你在 Kotlin 的工作變得更加困難。
        第二個問題,當(dāng)你讀取一個方法聲明時,你首先看到的是名字和返回類型,然后才是參數(shù)。
        在 Kotlin 中,方法的返回類型可能遠(yuǎn)在行尾,所以需要瀏覽很多代碼才能看到: 


        private fun getMetricValue(kafkaTemplate : KafkaTemplate<String, ByteArray>, metricName : String) : Double {
            ...
        }


        或者,如果參數(shù)是逐行格式的,則需要搜索。那么我們需要多少時間才能找到此方法的返回類型呢?


        @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<String, ByteArray> {
            val bootstrapServer = if (cloudMetadata.datacenter == "dc1") {
                bootstrapServersDc1
            }
            ...
        }


        第三個問題是 IDE 中的自動化支持不夠好。標(biāo)準(zhǔn)做法從類型名稱開始,并且很容易找到類型。一旦選擇一個類型,IDE 會提供一些關(guān)于變量名的建議,這些變量名是從選定的類型派生的,因此你可以快速輸入這樣的變量: 


        MongoExperimentsRepository repository


        Kotlin 盡管有 IntelliJ 這樣強(qiáng)大的 IDE,輸入變量仍然是很難的。如果你有多個存儲庫,在列表中很難實(shí)現(xiàn)正確的自動補(bǔ)全,這意味著你不得不手動輸入完整的變量名稱。


        repository : MongoExperimentsRepository


        伴生對象
        一位 Java 程序員來到 Kotlin 面前。
        “嗨,Kotlin。我是新來的,我可以使用靜態(tài)成員嗎?"他問。
         “不行。我是面向?qū)ο蟮模o態(tài)成員不是面向?qū)ο蟮?。?Kotlin 回答。
         “好吧,但我需要 MyClass 的 logger,我該怎么辦?” 
        “這個沒問題,使用伴生對象即可?!?/span>
         “那是什么東西?” “這是局限到你的類的單獨(dú)對象。把你的 logger 放在伴生對象中?!盞otlin解釋說。
         “我懂了。這樣對嗎?”


        class MyClass {
            companion object {
                val logger = LoggerFactory.getLogger(MyClass::class.java)
            }
        }


        “正確!”
         “很詳細(xì)的語法,”程序員看起來很疑惑,“但是沒關(guān)系,現(xiàn)在我可以像 MyClass.logger 這樣調(diào)用我的 logger,就像 Java 中的一個靜態(tài)成員?” 
        “嗯......是的,但它不是靜態(tài)成員!這里只有對象。把它看作是已經(jīng)實(shí)例化為單例的匿名內(nèi)部類。事實(shí)上,這個類并不是匿名的,它的名字是 Companion,但你可以省略這個名字??吹搅藛??這很簡單。"
        我很欣賞對象聲明的概念——單例很有用。但從語言中刪除靜態(tài)成員是不切實(shí)際的。在 Java 中我們使用靜態(tài) Logger 很經(jīng)典,它只是一個 Logger,所以我們不關(guān)心面向?qū)ο蟮募兌?。它能夠工作,從來沒有任何壞處。
        因?yàn)橛袝r候你必須使用靜態(tài)。舊版本 public static void main() 仍然是啟動 Java 應(yīng)用程序的唯一方式。


        class AppRunner {
            companion object {
                @JvmStatic fun main(args: Array<String>) {
                    SpringApplication.run(AppRunner::class.java*args)
                }
            }
        }


        集合字面量
        在Java中,初始化列表非常繁瑣:


        import java.util.Arrays;
        ...
        List<String> strings = Arrays.asList("Saab""Volvo");


        初始化地圖非常冗長,很多人使用 Guava:


        import com.google.common.collect.ImmutableMap;
        ...
        Map<StringString> string = ImmutableMap.of("firstName""John""lastName""Doe");


        在 Java 中,我們?nèi)匀辉诘却碌恼Z法來表達(dá)集合和映射。語法在許多語言中非常自然和方便。
        JavaScript:


        const list = ['Saab''Volvo']
        const map = {'firstName''John''lastName' : 'Doe'}


        Python:


        list = ['Saab''Volvo']
        map = {'firstName''John''lastName''Doe'}


        Groovy:


        def list = ['Saab''Volvo']
        def map = ['firstName''John''lastName''Doe']


        簡單來說,集合字面量的整齊語法就是你對現(xiàn)代編程語言的期望,特別是如果它是從頭開始創(chuàng)建的。Kotlin 提供了一系列內(nèi)置函數(shù),比如 listOf()、mutableListOf()、mapOf()、hashMapOf() 等等。
        Kotlin: 


        val list = listOf("Saab""Volvo")
        val map = mapOf("firstName" to "John""lastName" to "Doe")


        在地圖中,鍵和值與 to 運(yùn)算符配對,這很好。但為什么一直沒有得到廣泛使用呢?令人失望。
        Maybe
        函數(shù)式語言(比如 Haskell)沒有空值。相反,他們提供 Maybe monad(如果你不熟悉monad,請閱讀 Tomasz Nurkiewicz 的這篇文章:http://www.nurkiewicz.com/2016/06/functor-and-monad-examples-in-plain-java.html)。
        Maybe 很久以前就被 Scala 以 Option 引入到 JVM 世界,然后在 Java 8 中被采用為 Optional。如今,Optional 是在 API 邊界處理返回類型中的空值的非常流行的方式。
        Kotlin 中沒有 Optional 的等價物,所以你大概應(yīng)該使用 Kotlin 的可空類型。讓我們來調(diào)查一下這個問題。
        通常情況下,當(dāng)你有一個 Optional 的時候,你想要應(yīng)用一系列無效的轉(zhuǎn)換。
        例如,在 Java 中: 


        public int parseAndInc(String number) {
            return Optional.ofNullable(number)
                           .map(Integer::parseInt)
                           .map(it -> it + 1)
                           .orElse(0);
        }


        在 Kotlin 中,為了映射你可以使用 let 函數(shù):


        fun parseAndInc(number: String?)Int {
            return number.let { Integer.parseInt(it) }
                         .let { it -> it + 1 } ?: 0
        }


        上面的代碼是錯誤的,parseInt() 會拋出 NPE 。map() 僅在有值時執(zhí)行。否則,Null 就會跳過,這就是為什么 map() 如此方便。不幸的是,Kotlin 的 let 不會那樣工作。它從左側(cè)的所有內(nèi)容中調(diào)用,包括空值。
        為了保證這個代碼 Null 安全,你必須在每個代碼之前添加 let: 


        fun parseAndInc(number: String?)Int {
            return number?.let { Integer.parseInt(it) }
                         ?.let { it -> it + 1 } ?: 0
        }


        現(xiàn)在,比較 Java 和 Kotlin 版本的可讀性。你更傾向哪個?
        數(shù)據(jù)類
        數(shù)據(jù)類是 Kotlin 在實(shí)現(xiàn) Value Objects 時使用的方法,以減少 Java 中不可避免的樣板問題。
        例如,在 Kotlin 中,你只寫一個 Value Object :


        data class User(val name: String, val age: Int)


        Kotlin 對 equals()、hashCode()、toString() 以及 copy() 有很好的實(shí)現(xiàn)。在實(shí)現(xiàn)簡單的DTO 時它非常有用。但請記住,數(shù)據(jù)類帶有嚴(yán)重的局限性。你無法擴(kuò)展數(shù)據(jù)類或者將其抽象化,所以你可能不會在核心模型中使用它們。
        這個限制不是 Kotlin 的錯。在 equals() 沒有違反 Liskov 原則的情況下,沒有辦法產(chǎn)生正確的基于價值的數(shù)據(jù)。
        這也是為什么 Kotlin 不允許數(shù)據(jù)類繼承的原因。
        開放類
        Kotlin 類默認(rèn)為 final。如果你想擴(kuò)展一個類,必須添加 open 修飾符。
        繼承語法如下所示: 


        open class Base
        class Derived : Base()


        Kotlin 將 extends 關(guān)鍵字更改為: 運(yùn)算符,該運(yùn)算符用于將變量名稱與其類型分開。那么再回到 C ++語法?對我來說這很混亂。
        這里有爭議的是,默認(rèn)情況下類是 final。也許 Java 程序員過度使用繼承,也許應(yīng)該在考慮擴(kuò)展類之前考慮三次。但我們生活在框架世界,Spring 使用 cglib、jassist 庫為你的 bean 生成動態(tài)代理。Hibernate 擴(kuò)展你的實(shí)體以啟用延遲加載。
        如果你使用 Spring,你有兩種選擇。你可以在所有 bean 類的前面添加 open,或者使用這個編譯器插件: 


        buildscript {
            dependencies {
                classpath group: 'org.jetbrains.kotlin', name: 'kotlin-allopen', version: "$versions.kotlin"
            }
        }


        陡峭的學(xué)習(xí)曲線
        如果你認(rèn)為自己有 Java 基礎(chǔ)就可以快速學(xué)習(xí) Kotlin,那你就錯了。Kotlin 會讓你陷入深淵,事實(shí)上,Kotlin 的語法更接近 Scala。這是一項(xiàng)賭注,你將不得不忘記 Java 并切換到完全不同的語言。
        相反,學(xué)習(xí) Groovy 是一個愉快的過程。Java 代碼是正確的 Groovy 代碼,因此你可以通過將文件擴(kuò)展名從 .java 更改為 .groovy。
        最后的想法
        學(xué)習(xí)新技術(shù)就像一項(xiàng)投資。我們投入時間,新技術(shù)讓我們得到回報。但我并不是說 Kotlin 是一種糟糕的語言,只是在我們的案例中,成本遠(yuǎn)超收益。
        以上內(nèi)容編譯自 From Java to Kotlin and Back Again,作者 Kotlin ketckup。
        他是一名具有15年以上專業(yè)經(jīng)驗(yàn)的軟件工程師,專注于JVM 。在 Allegro,他是一名開發(fā)團(tuán)隊負(fù)責(zé)人,JaVers 項(xiàng)目負(fù)責(zé)人,Spock 倡導(dǎo)者。此外,他還是 allegro.tech/blog 的主編。
        本文一出就引發(fā)了業(yè)內(nèi)的廣泛爭議,Kotlin 語言擁護(hù)者 Márton Braun 就表示了強(qiáng)烈的反對。
        Márton Braun 十分喜歡 Kotlin 編程,目前他在 StackOverflow 上 Kotlin 標(biāo)簽的最高用戶列表中排名第三,并且是兩個開源 Kotlin 庫的創(chuàng)建者,最著名的是 MaterialDrawerKt。此外他還是 Autosoft 的 Android 開發(fā)人員,目前正在布達(dá)佩斯技術(shù)經(jīng)濟(jì)大學(xué)攻讀計算機(jī)工程碩士學(xué)位。

        以下就是他針對上文的反駁:
        當(dāng)我第一次看到這篇文章時,我就想把它轉(zhuǎn)發(fā)出來看看大家會怎么想,我肯定它會是一個有爭議的話題。后來我讀了這篇文章,果然證明了它是一種主觀的、不真實(shí)的、甚至有些居高臨下的偏見。
        有些人已經(jīng)在原貼下進(jìn)行了合理的批評,對此我也想表達(dá)一下自己的看法。
        名稱遮蔽
        “IDEA 團(tuán)隊”(或者 Kotlin 插件團(tuán)隊)和“Kotlin 團(tuán)隊”肯定是同樣的人,我從不認(rèn)為內(nèi)部沖突會是個好事。語言提供這個功能給你,你需要的話就使用,如果討厭,調(diào)整檢查設(shè)置就是了。
        類型推斷
        Kotlin 的類型推斷無處不在,作者說的 Java 10 同樣可以簡直是在開玩笑。
        Kotlin 的方式超越了推斷局部變量類型或返回表達(dá)式體的函數(shù)類型。這里介紹的這兩個例子是那些剛剛看過關(guān)于 Kotlin 的第一次介紹性講話的人會提到的,而不是那些花了半年學(xué)習(xí)該語言的人。
        例如,你怎么能不提 Kotlin 推斷泛型類型參數(shù)的方式?這不是 Kotlin 的一次性功能,它深深融入了整個語言。
        編譯時 Null 安全
        這個批評是對的,當(dāng)你與 Java 代碼進(jìn)行互操作時,Null 安全性確實(shí)被破壞了。該語言背后的團(tuán)隊曾多次聲明,他們最初試圖使 Java 可為空的每種類型,但他們發(fā)現(xiàn)它實(shí)際上讓代碼變得更糟糕。
        Kotlin 不比 Java 更差,你只需要注意使用給定庫的方式,就像在 Java 中使用它一樣,因?yàn)樗]有不去考慮 Null 安全。如果 Java 庫關(guān)心 Null 安全性,則它們會有許多支持注釋可供添加。
        也許可以添加一個編譯器標(biāo)志,使每種 Java 類型都可以為空,但這對 Kotlin 團(tuán)隊來說不得不花費(fèi)大量額外資源。
        類名稱字面常量
        :: class 為你提供了一個 KClass 實(shí)例,以便與 Kotlin 自己的反射 API 一起使用,而:: class.java為你提供了用于 Java 反射的常規(guī) Java 類實(shí)例。
        反向類型聲明
        為了清楚起見,顛倒的順序是存在的,這樣你就可以以合理的方式省略顯式類型。冒號只是語法,這在現(xiàn)代語言中是相當(dāng)普遍的一種,比如 Scala、Swift 等。
        我不知道作者在使用什么 IntelliJ,但我使用的變量名稱和類型都能夠自動補(bǔ)全。對于參數(shù),IntelliJ 甚至?xí)o你提供相同類型的名稱和類型的建議,這實(shí)際上比 Java 更好。
        伴生對象
        原文中說:
        有時候你必須使用靜態(tài)。舊版本 public static void main() 仍然是啟動 Java 應(yīng)用程序的唯一方式。


        class AppRunner {
            companion object {
                @JvmStatic fun main(args: Array<String>) {
                    SpringApplication.run(AppRunner::class.java*args)
                }
            }
        }


        實(shí)際上,這不是啟動 Java 應(yīng)用程序的唯一方式。你可以這樣做:


         fun main(args:Array <String>){ SpringApplication.run(AppRunner :: class.java,* args)} 


        或者這樣:


         fun main(args:Array <String>){ runApplication <AppRunner>(* args)}


        集合字面量
        你可以在注釋中使用數(shù)組文字。但是,除此之外,這些集合工廠的功能非常簡潔,而且它們是另一種“內(nèi)置”到該語言的東西,而它們實(shí)際上只是庫函數(shù)。
        你只是抱怨使用:進(jìn)行類型聲明。而且,為了獲得它不必是單獨(dú)的語言結(jié)構(gòu)的好處,它只是一個任何人都可以實(shí)現(xiàn)的功能。
        Maybe
        如果你喜歡 Optional ,你可以使用它。Kotlin 在 JVM 上運(yùn)行。
        對于代碼確實(shí)這有些難看。但是你不應(yīng)該在 Kotlin 代碼中使用 parseInt,而應(yīng)該這樣做(我不知道你使用該語言的 6 個月中為何錯過這個)。你為什么要明確地命名一個 Lambda 參數(shù)呢?
        數(shù)據(jù)類
        原文中說:
        這個限制不是 Kotlin 的錯。在 equals() 沒有違反 Liskov 原則的情況下,沒有辦法產(chǎn)生正確的基于價值的數(shù)據(jù)。
        這就是為什么 Kotlin 不允許數(shù)據(jù)類繼承的原因。
        我不知道你為什么提出這個問題。如果你需要更復(fù)雜的類,你仍然可以創(chuàng)建它們并手動維護(hù)它們的 equals、hashCode 等方法。數(shù)據(jù)類僅僅是一個簡單用例的便捷方式,對于很多人來說這很常見。
        公開類
        作者再次鄙視了,對此我實(shí)在無話可說。
        陡峭的學(xué)習(xí)曲線
        作者認(rèn)為學(xué)習(xí) Kotlin 很難, 但是我個人并不這么認(rèn)為。
        最后的想法
        從作者列舉的例子中,我感覺他只是了解語言的表面。
        很難想象他對此有投入很多時間。
        最近的語言排行,java依然排在第一,在語言排行榜上,Koltin已被甩到10名之外!

        關(guān)注公眾號【Java技術(shù)江湖】后回復(fù)“PDF”即可領(lǐng)取200+頁的《Java工程師面試指南》

        強(qiáng)烈推薦,幾乎涵蓋所有Java工程師必知必會的知識點(diǎn),不管是復(fù)習(xí)還是面試,都很實(shí)用。



        瀏覽 26
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            99视频在线精品免费观看2 | 好吊操免费视频 | 涩涩涩涩色 | 成人免费看片 视频 | 人人射人人舔 | 日本親子亂子倫XXXX50路 | 色戒未删减版在线观看免费版下载 | 欧美亚洲国产日韩 | 91色一区二区三区 | 成人色情电影在线观看 |