當前位置:
首頁 > 知識 > 在沒有 Kotlin 的世界與 Android 共舞

在沒有 Kotlin 的世界與 Android 共舞

在沒有 Kotlin 的世界與 Android 共舞


作為一個專業的工程師,你不能在沒有同意的情況下私自去使用那些時髦的技術。我知道這聽起來非常恐怖,特別當你已經品嘗到 Kotlin 的好處時,不過不要失去生活的信念。 -- Piotr ?lesarew

本文導航

  • -數據類 …… 11%

  • -Lambda 表達式 …… 30%

  • -數據操作 …… 53%

  • -擴展函數 …… 76%

編譯自: https://medium.com/proandroiddev/living-android-without-kotlin-db7391a2b170

作者: Piotr ?lesarew

譯者: DockerChen

開始投入一件事比遠離它更容易。?—?Donald Rumsfeld

沒有 Kotlin 的生活就像在觸摸板上玩魔獸爭霸 3。購買滑鼠很簡單,但如果你的新僱主不想讓你在生產中使用 Kotlin,你該怎麼辦?

下面有一些選擇。

  • 與你的產品負責人爭取獲得使用 Kotlin 的權利。

  • 使用 Kotlin 並且不告訴其他人因為你知道最好的東西是只適合你的。

  • 擦掉你的眼淚,自豪地使用 Java。

想像一下,你在和產品負責人的鬥爭中失敗,作為一個專業的工程師,你不能在沒有同意的情況下私自去使用那些時髦的技術。我知道這聽起來非常恐怖,特別當你已經品嘗到 Kotlin 的好處時,不過不要失去生活的信念。

在文章接下來的部分,我想簡短地描述一些 Kotlin 的特徵,使你通過一些知名的工具和庫,可以應用到你的 Android 里的 Java 代碼中去。對於 Kotlin 和 Java 的基本認識是需要的。


數據類

我想你肯定已經喜歡上 Kotlin 的數據類。對於你來說,得到 equals()、 hashCode()、 toString() 和 copy() 這些是很容易的。具體來說,data 關鍵字還可以按照聲明順序生成對應於屬性的 componentN() 函數。 它們用於解構聲明。


data class Person(val name: String)

val (riddle) = Person("Peter")

println(riddle)

你知道什麼會被列印出來嗎?確實,它不會是從 Person 類的 toString() 返回的值。這是解構聲明的作用,它賦值從 name 到 riddle。使用園括弧 (riddle) 編譯器知道它必須使用解構聲明機制。


val (riddle): String = Person("Peter").component1()

println(riddle) // prints Peter)

這個代碼沒編譯。它就是展示了構造聲明怎麼工作的。

正如你可以看到 data 關鍵字是一個超級有用的語言特性,所以你能做什麼把它帶到你的 Java 世界? 使用注釋處理器並修改抽象語法樹(Abstract Syntax Tree)。 如果你想更深入,請閱讀文章末尾列出的文章(Project Lombok—?Trick Explained)。

使用項目 Lombok 你可以實現 data關鍵字所提供的幾乎相同的功能。 不幸的是,沒有辦法進行解構聲明。


import lombok.Data;

@Data class Person {

final String name;

}

@Data 註解生成 equals()、hashCode() 和 toString()。 此外,它為所有欄位創建 getter,為所有非最終欄位創建setter,並為所有必填欄位(final)創建構造函數。 值得注意的是,Lombok 僅用於編譯,因此庫代碼不會添加到您的最終的 .apk。


Lambda 表達式

Android 工程師有一個非常艱難的生活,因為 Android 中缺乏 Java 8 的特性,而且其中之一是 lambda 表達式。 Lambda 是很棒的,因為它們為你減少了成噸的樣板。 你可以在回調和流中使用它們。 在 Kotlin 中,lambda 表達式是內置的,它們看起來比它們在 Java 中看起來好多了。 此外,lambda 的位元組碼可以直接插入到調用方法的位元組碼中,因此方法計數不會增加。 它可以使用內聯函數。


button.setOnClickListener { println("Hello World") }

最近 Google 宣布在 Android 中支持 Java 8 的特性,由於 Jack 編譯器,你可以在你的代碼中使用 lambda。還要提及的是,它們在 API 23 或者更低的級別都可用。


button.setOnClickListener(view -> System.out.println("Hello World!"));

怎樣使用它們?就只用添加下面幾行到你的 build.gradle 文件中。


defaultConfig {

jackOptions {

enabled true

}

}

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

如果你不喜歡用 Jack 編譯器,或者你由於一些原因不能使用它,這裡有一個不同的解決方案提供給你。Retrolambda 項目允許你在 Java 7,6 或者 5 上運行帶有 lambda 表達式的 Java 8 代碼,下面是設置過程。


dependencies {

classpath "me.tatarka:gradle-retrolambda:3.4.0"

}

apply plugin: "me.tatarka.retrolambda"

compileOptions {

sourceCompatibility JavaVersion.VERSION_1_8

targetCompatibility JavaVersion.VERSION_1_8

}

正如我前面提到的,在 Kotlin 下的 lambda 內聯函數不增加方法計數,但是如何在 Jack 或者 Retrolambda 下使用它們呢? 顯然,它們不是沒成本的,隱藏的成本如下。

在沒有 Kotlin 的世界與 Android 共舞

該表展示了使用不同版本的 Retrolambda 和 Jack 編譯器生成的方法數量。該比較結果來自 Jake Wharton 的「探索 Java 的隱藏成本[1]」 技術討論之中。


數據操作

Kotlin 引入了高階函數作為流的替代。 當您必須將一組數據轉換為另一組數據或過濾集合時,它們非常有用。


fun foo(persons: MutableList) {

persons.filter { it.age >= 21 }

.filter { it.name.startsWith("P") }

.map { it.name }

.sorted()

.forEach(::println)

}

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

流也由 Google 通過 Jack 編譯器提供。 不幸的是,Jack 不使用 Lombok,因為它在編譯代碼時跳過生成中間的 .class 文件,而 Lombok 卻依賴於這些文件。


void foo(List persons) {

persons.stream()

.filter(it -> it.getAge() >= 21)

.filter(it -> it.getName().startsWith("P"))

.map(Person::getName)

.sorted()

.forEach(System.out::println);

}

class Person {

final private String name;

final private int age;

public Person(String name, int age) {

this.name = name;

this.age = age;

}

String getName() { return name; }

int getAge() { return age; }

}

這簡直太好了,所以 catch 在哪裡? 令人悲傷的是,流從 API 24 才可用。谷歌做了好事,但哪個應用程序有用 minSdkVersion = 24?

幸運的是,Android 平台有一個很好的提供許多很棒的庫的開源社區。Lightweight-Stream-API 就是其中的一個,它包含了 Java 7 及以下版本的基於迭代器的流實現。


import lombok.Data;

import com.annimon.stream.Stream;

void foo(List persons) {

Stream.of(persons)

.filter(it -> it.getAge() >= 21)

.filter(it -> it.getName().startsWith("P"))

.map(Person::getName)

.sorted()

.forEach(System.out::println);

}

@Data class Person {

final String name;

final int age;

}

上面的例子結合了 Lombok、Retrolambda 和 Lightweight-Stream-API,它看起來幾乎和 Kotlin 一樣棒。使用靜態工廠方法允許您將任何 Iterable 轉換為流,並對其應用 lambda,就像 Java 8 流一樣。 將靜態調用 Stream.of(persons) 包裝為 Iterable 類型的擴展函數是完美的,但是 Java 不支持它。


擴展函數

擴展機制提供了向類添加功能而無需繼承它的能力。 這個眾所周知的概念非常適合 Android 世界,這就是 Kotlin 在該社區很受歡迎的原因。

有沒有技術或魔術將擴展功能添加到你的 Java 工具箱? 因 Lombok,你可以使用它們作為一個實驗功能。 根據 Lombok 文檔的說明,他們想把它從實驗狀態移出,基本上沒有什麼變化的話很快。 讓我們重構最後一個例子,並將 Stream.of(persons) 包裝成擴展函數。


import lombok.Data;

import lombok.experimental.ExtensionMethod;

@ExtensionMethod(Streams.class)

public class Foo {

void foo(List persons) {

persons.toStream()

.filter(it -> it.getAge() >= 21)

.filter(it -> it.getName().startsWith("P"))

.map(Person::getName)

.sorted()

.forEach(System.out::println);

}

}

@Data class Person {

final String name;

final int age;

}

class Streams {

static Stream toStream(List list) {

return Stream.of(list);

}

}

所有的方法是 public、static 的,並且至少有一個參數的類型不是原始的,因而是擴展方法。 @ExtensionMethod 註解允許你指定一個包含你的擴展函數的類。 你也可以傳遞數組,而不是使用一個 .class 對象。



我完全知道我的一些想法是非常有爭議的,特別是 Lombok,我也知道,有很多的庫,可以使你的生活更輕鬆。請不要猶豫在評論里分享你的經驗。乾杯!

在沒有 Kotlin 的世界與 Android 共舞



作者簡介:

Coder and professional dreamer @ Grid Dynamics



via: https://medium.com/proandroiddev/living-android-without-kotlin-db7391a2b170

作者:Piotr ?lesarew[2] 譯者:DockerChen 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

  • [1]: 探索 Java 的隱藏成本 - http://jakewharton.com/exploring-java-hidden-costs/

  • [2]: Piotr ?lesarew - https://hackernoon.com/@piotr.slesarew?source=post_header_lockup

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Linux技術 的精彩文章:

TAG:Linux技術 |

您可能感興趣

Kotlin Android 環境搭建
Gradle Kotlin DSL的accessors 生成問題
Spring Boot與Kotlin 使用MongoDB資料庫
Kotlin打造Android路由框架
Spring Boot與Kotlin使用Spring-data-jpa簡化數據訪問層
Android開發者是時候轉向Kotlin了
Kotlin和Swift語言在Redmonk榜上排名大幅提升
Kotlin項目下的Retrofit2網路請求框架
Kotlin 類和對象
Google發布Android KTX預覽版,它能為Kotlin開發者做些什麼?
Kotlin 泛型
Canonical宣布Kotlin編程語言Snap包格式上線
Kotlin 介面
Kotlin 繼承
Kotlin 語言獲Linux通行證
開發 iOS 應用,Kotlin Native 是否夠格?
Kotlin 擴展
Kotlin語言Web庫又添一虎將:Kweb
Kotlin 編程
從源碼角度分析 Kotlin by lazy 的實現