Java 8 具有 Retrolambda 的子集

Retrolambda 允許你在 Java 7,6 或 5 上執行帶有 lambda 表示式,方法引用和 try-with-resources 語句的 Java 8 程式碼。它通過轉換 Java 8 編譯的位元組碼來實現,以便它可以在較舊的 Java 執行時上執行。

移植語言功能:

  • Lambda 表示式通過將它們轉換為匿名內部類來向後移植。這包括優化對無狀態 lambda 表示式使用單例例項以避免重複的物件分配。方法引用基本上只是 lambda 表示式的語法糖,它們以相同的方式向後移植。

  • 如果目標位元組碼版本低於 Java 7,則通過刪除對 Throwable.addSuppressed 的呼叫來反向嘗試資源語句。如果你希望記錄被抑制的異常而不是吞下,請建立一個功能請求,我們將使其可配置。

  • 如果目標位元組碼版本低於 Java 7,則 Objects.requireNonNull 呼叫將替換為對 Object.getClass 的呼叫。由 JDK 9 生成的合成空值檢查使用 Objects.requireNonNull,而早期的 JDK 版本使用 Object.getClass

  • 也可選擇:

    1. 通過將預設方法複製到伴隨類(介面名稱+“$”)作為靜態方法,用抽象方法替換介面中的預設方法,以及通過向實現該介面的所有類新增必要的方法實現來反向移植預設方法。

    2. 通過將靜態方法移動到伴隨類(介面名稱+“$”)並通過更改所有方法呼叫來呼叫新方法位置來對介面上的靜態方法進行反向移植。

已知限制:

  • 不支援 Java 8 API

  • 在介面上向後移植預設方法和靜態方法需要所有後向移植的介面和實現它們的所有類或呼叫它們的靜態方法一起向後移植,一次執行 Retrolambda。換句話說,你必須始終進行乾淨的構建。此外,向後移植預設方法不適用於模組或依賴關係邊界。

  • 如果未來的 JDK 8 構建停止為每個 invokedynamic 呼叫生成一個新類,可能會中斷。Retrolambda 的工作方式是捕獲 java.lang.invoke.LambdaMetafactory 動態生成的位元組碼,因此對該機制的優化可能會破壞 Retrolambda。

Retrolambda gradle 外掛將使用 Retrolambda 自動構建你的 Android 專案。最新版本可以在釋出頁面上找到。

用法:

  1. 下載並安裝 jdk8
  2. 將以下內容新增到你的 build.gradle
buildscript {
  repositories {
     mavenCentral()
  }

  dependencies {
     classpath 'me.tatarka:gradle-retrolambda:<latest version>'
  }
}

// Required because retrolambda is on maven central
repositories {
  mavenCentral()
}

apply plugin: 'com.android.application' //or apply plugin: 'java'
apply plugin: 'me.tatarka.retrolambda'

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

已知的問題:

  • Lint 在有 lambda 的 java 檔案上失敗。Android 的 lint 不懂 java 8 語法,會無聲或大聲失敗。現在有一個實驗分叉可以解決這個問題。

  • 使用 Google Play 服務會導致 Retrolambda 失敗。版本 5.0.77 包含與 Retrolambda 不相容的位元組碼。這應該在較新版本的播放服務中修復,如果你可以更新,那應該是首選的解決方案。要解決此問題,你可以使用早期版本(如 4.4.52)或將 -noverify 新增到 jvm args。

retrolambda {
  jvmArgs '-noverify'
}