Java on Android

Android supports all Java 7 language features and a subset of Java 8 language features that vary by platform version. This page describes the new language features you can use, how to properly configure your project to use them and any known issues you may encounter.

Java 8 features subset with Retrolambda

Retrolambda lets you run Java 8 code with lambda expressions, method references and try-with-resources statements on Java 7, 6 or 5. It does this by transforming your Java 8 compiled bytecode so that it can run on an older Java runtime.

Backported Language Features:

  • Lambda expressions are backported by converting them to anonymous inner classes. This includes the optimisation of using a singleton instance for stateless lambda expressions to avoid repeated object allocation. Method references are basically just syntax sugar for lambda expressions and they are backported in the same way.

  • Try-with-resources statements are backported by removing calls to Throwable.addSuppressed if the target bytecode version is below Java 7. If you would like the suppressed exceptions to be logged instead of swallowed, please create a feature request and we'll make it configurable.

  • Objects.requireNonNull calls are replaced with calls to Object.getClass if the target bytecode version is below Java 7. The synthetic null checks generated by JDK 9 use Objects.requireNonNull, whereas earlier JDK versions used Object.getClass.

  • Optionally also:

    1. Default methods are backported by copying the default methods to a companion class (interface name + "$") as static methods, replacing the default methods in the interface with abstract methods, and by adding the necessary method implementations to all classes which implement that interface.

    2. Static methods on interfaces are backported by moving the static methods to a companion class (interface name + "$"), and by changing all methods calls to call the new method location.

Known Limitations:

  • Does not backport Java 8 APIs

  • Backporting default methods and static methods on interfaces requires all backported interfaces and all classes which implement them or call their static methods to be backported together, with one execution of Retrolambda. In other words, you must always do a clean build. Also, backporting default methods won't work across module or dependency boundaries.

  • May break if a future JDK 8 build stops generating a new class for each invokedynamic call. Retrolambda works so that it captures the bytecode that java.lang.invoke.LambdaMetafactory generates dynamically, so optimisations to that mechanism may break Retrolambda.

Retrolambda gradle plugin will automatically build your android project with Retrolambda. The latest version can be found on the releases page.

Usage:

  1. Download and install jdk8
  2. Add the following to your 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
    }
}

Known Issues:

  • Lint fails on java files that have lambdas. Android's lint doesn't understand java 8 syntax and will fail silently or loudly. There is now an experimental fork that fixes the issue.

  • Using Google Play Services causes Retrolambda to fail. Version 5.0.77 contains bytecode that is incompatible with Retrolambda. This should be fixed in newer versions of play services, if you can update, that should be the preferred solution. To work around this issue, you can either use an earlier version like 4.4.52 or add -noverify to the jvm args.

retrolambda {
  jvmArgs '-noverify'
}