Cómo usar las funciones y las APIs del lenguaje Java 8

El complemento de Android para Gradle 3.0.0 y las versiones posteriores admiten todas las funciones del lenguaje Java 7 y un subconjunto de funciones del lenguaje Java 8 que varían según la versión de la plataforma. Cuando compilas tu app con el complemento de Android para Gradle 4.0.0 y versiones posteriores, puedes usar algunas APIs de lenguaje Java 8 sin requerir un nivel de API mínimo para la app.

En esta página, se describen las funciones del lenguaje Java 8 que puedes utilizar, la manera de configurar correctamente tu proyecto para usarlas y los problemas conocidos que puedes experimentar. Mira el siguiente video para obtener una descripción general de las funciones del lenguaje Java 8.

El complemento de Android para Gradle proporciona compatibilidad integrada para el uso de ciertas funciones del lenguaje Java 8 y bibliotecas de terceros que las usan. La cadena de herramientas predeterminada implementa las funciones nuevas del lenguaje realizando transformaciones de código de bytes, con el nombre desugar, como parte de la compilación con D8 o R8 de archivos de clases en código DEX, como se muestra en la Figura 1.

Compatibilidad con funciones del lenguaje Java 8 mediante transformaciones de código de bytes "desugar"
Figura 1: Compatibilidad con funciones del lenguaje Java 8 mediante transformaciones de código de bytes desugar

Compatibilidad con funciones del lenguaje Java 8 (complemento de Android para Gradle 3.0.0 y versiones posteriores)

Para comenzar a usar las funciones del lenguaje Java 8 compatibles, haz lo siguiente:

  1. Actualiza el complemento de Android para Gradle a la versión 3.0.0 o una posterior.
  2. Para cada módulo que utilice funciones del lenguaje Java 8 (ya sea en su código fuente o a través de dependencias), actualiza el archivo build.gradle o build.gradle.kts del módulo, como se muestra a continuación:

Kotlin

android {
    ...
    // Configure only for each module that uses Java 8
    // language features (either in its source code or
    // through dependencies).
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Groovy

android {
    ...
    // Configure only for each module that uses Java 8
    // language features (either in its source code or
    // through dependencies).
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Cuando compilas tu app con el complemento de Android para Gradle 3.0.0 y versiones posteriores, el complemento no es compatible con todas las funciones del lenguaje Java 8. Las siguientes funciones del lenguaje están disponibles en cualquier nivel de API:

Función del lenguaje Java 8 Notas
Expresiones lambda Android no admite la serialización de expresiones lambda.
Referencias de métodos  
Anotaciones de tipos La información de anotación de tipos solo está disponible durante el tiempo de compilación y no en el de ejecución. La plataforma admite TYPE en el nivel de API 24 y versiones anteriores, pero no ElementType.TYPE_USE ni ElementType.TYPE_PARAMETER.
Métodos de interfaz predeterminados y estáticos  
Repetición de anotaciones  

Además de estas funciones del lenguaje Java 8, las versiones 3.0.0 y posteriores del complemento de Android para Gradle extienden la compatibilidad con try-with-resources para todos los niveles de API de Android.

Desugar no admite MethodHandle.invoke ni MethodHandle.invokeExact. Si tu código fuente o una de las dependencias del módulo usan uno de estos métodos, debes especificar minSdkVersion 26 o una versión posterior. De lo contrario, recibirás el siguiente error:

Dex: Error converting bytecode to dex:
Cause: signature-polymorphic method called without --min-sdk-version >= 26

En algunos casos, es posible que tu módulo no use los métodos invoke ni invokeExact, incluso si forman parte de una dependencia de biblioteca. Para seguir usando esa biblioteca con minSdkVersion 25 o anteriores, habilita la reducción de código para quitar los métodos sin utilizar. Si eso no funciona, procura usar una biblioteca alternativa que no emplee los métodos no admitidos.

Las funciones de expansión de sintaxis del lenguaje Java 8 o superior que están disponibles en el complemento de Android para Gradle 3.0.0 y versiones posteriores no permiten que las clases y APIs adicionales (como java.util.stream.*) estén disponibles para su uso en versiones anteriores de Android. La compatibilidad con la expansión de sintaxis parcial de la API de Java está disponible en el complemento de Android para Gradle 4.0.0 o versiones posteriores, como se describe en la siguiente sección.

Compatibilidad con la expansión de sintaxis de APIs en Java 8 y versiones posteriores (complemento de Android para Gradle 4.0.0 y versiones posteriores)

Si compilas tu app con el complemento de Android para Gradle 4.0.0 o versiones posteriores, el complemento extiende la compatibilidad para usar varias APIs del lenguaje Java 8 sin requerir un nivel de API mínimo para la app. Con el complemento de Android para Gradle 7.4.0 o versiones posteriores, varias APIs del lenguaje Java 11 también están disponibles con la biblioteca de expansión de sintaxis 2.0.0 o versiones posteriores.

Esa compatibilidad adicional para versiones anteriores de la plataforma es posible porque el complemento 4.0.0 y versiones posteriores amplía el motor de expansión de sintaxis para poder expandir la sintaxis de las APIs del lenguaje Java. Puedes incluir APIs de lenguaje estándar que solo estaban disponibles en las versiones recientes de Android (como java.util.streams) en apps que admiten versiones anteriores de Android.

El siguiente conjunto de APIs es compatible cuando se compila tu app con el complemento de Android para Gradle 4.0.0 o una versión posterior:

  • Flujos secuenciales (java.util.stream)
  • Un subconjunto de java.time
  • java.util.function
  • Adiciones recientes a java.util.{Map,Collection,Comparator}
  • Opcional (java.util.Optional, java.util.OptionalInt y java.util.OptionalDouble) y algunas clases nuevas
  • Algunas adiciones a java.util.concurrent.atomic (métodos nuevos en AtomicInteger, AtomicLong y AtomicReference)
  • ConcurrentHashMap (con correcciones de errores para Android 5.0)

Con el complemento de Android para Gradle 7.4.0 o versiones posteriores, se admiten APIs de Java 11 adicionales, como un subconjunto del paquete java.nio.file.

Para obtener una lista completa de las APIs compatibles, visita la página sobre APIs de Java 8 y versiones posteriores disponibles a través de la expansión de sintaxis y APIs de Java 11 y versiones posteriores disponibles a través de la expansión de sintaxis.

Para admitir esas APIs de lenguaje, el complemento compila un archivo DEX separado que contiene una implementación de las APIs faltantes y lo incluye en tu app. El proceso de expansión de sintaxis reescribe el código de tu app para usar esa biblioteca en el tiempo de ejecución.

Para habilitar la compatibilidad con estas APIs de lenguaje en cualquier versión de la plataforma de Android, sigue estos pasos:

  1. Actualiza el complemento de Android para Gradle a la versión 4.0.0 (o una posterior).
  2. Incluye lo siguiente en el archivo build.gradle o build.gradle.kts del módulo de la app:

Kotlin

android {
    defaultConfig {
        // Required when setting minSdkVersion to 20 or lower
        multiDexEnabled = true
    }

    compileOptions {
        // Flag to enable support for the new language APIs

        // For AGP 4.1+
        isCoreLibraryDesugaringEnabled = true
        // For AGP 4.0
        // coreLibraryDesugaringEnabled = true

        // Sets Java compatibility to Java 8
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

dependencies {
    // For AGP 7.4+
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
    // For AGP 7.3
    // coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.3")
    // For AGP 4.0 to 7.2
    // coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.9")
}

Groovy

android {
    defaultConfig {
        // Required when setting minSdkVersion to 20 or lower
        multiDexEnabled true
    }

    compileOptions {
        // Flag to enable support for the new language APIs
        coreLibraryDesugaringEnabled true
        // Sets Java compatibility to Java 8
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    // For AGP 7.4+
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
    // For AGP 7.3
    // coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.3'
    // For AGP 4.0 to 7.2
    // coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.9'
}

Ten en cuenta que también es posible que debas incluir el fragmento de código anterior en un archivo build.gradle o build.gradle.kts del módulo de biblioteca en los siguientes casos:

  • Las pruebas de instrumentación del módulo de biblioteca usan estas APIs de lenguaje (ya sea directamente o a través del módulo de biblioteca o sus dependencias). Por lo tanto, las APIs faltantes se proporcionan para el APK de la prueba de instrumentación.

  • Lo mejor es ejecutar lint en el módulo de biblioteca de forma aislada. Esto permite que lint reconozca los usos válidos de las APIs de lenguaje y evite informar advertencias falsas.

Además, ten en cuenta que la expansión de sintaxis de API se puede combinar con reducción, pero solo cuando se usa el reductor R8.

Versiones

En la siguiente tabla, se muestran las versiones de la biblioteca de la API de Java 8 y versiones posteriores, y la versión mínima del complemento de Android para Gradle que admite cada versión:

Versión Versión mínima del complemento de Android para Gradle
1.1.9 4.0.0
1.2.3 7.3.0
2.0.3 7.4.0-alpha10

Para obtener detalles sobre las versiones de la biblioteca de la API de Java 8 o superior, consulta el archivo CHANGELOG.md en el repositorio desugar_jdk_libs de GitHub.