Enable Java 8 features in Android with these libraries

Since Android N, some of the Java 8 language features are finally supported thanks to the new Jack & Jill compiler toolchain. This however comes with several limitations like for example an inability to use the new compiler along with the data binding support library or limited annotations support. But that doesn’t mean that you should give up on advanced language features of Java 8 at all. In this post, I’ll introduce you to a way how to enable Java 8 features in Android by using four libraries back-porting Java 8 functionality to lower Java versions.

Java 8 features in Android M (6.0) and lower

The release of Java 8 brought a lot new into the language. Among the most important features, there are lambda expressions, method references, streams, and the new date and time API.

At the moment, with the new Jack & Jill compiler toolchain still in early development, it’s probably wiser to stay with the old and well-known Java 7. Luckily, several libraries exist, back-porting the Java 8 features in Android. Let’s have a look at how they can help you develop more effectively with the new language features they bring.

Lambda expressions

One of the most expected features in Java language, the lambda expressions, have finally arrived with the release of Java 8. Lambda expressions, simply put, allow you to pass around blocks of code with parameters.

They can be used in place of anonymous instances of classes for example when defining an action to be executed upon a button click. To demonstrate, examples of setting an onClick listener on a button using an anonymous class and lambda expression follows:

// Anonymous class approach:
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // onClick action here
    }
});

// Lambda expresssion approach:
button.setOnClickListener(view -> {
    // onClick action here
});

To learn more about lambda expressions, please refer to my previous posts Lambda expressions in Java 8 and Lambda expressions in Android.

Lambda expressions in Java 6 and 7 with Retrolambda

Enabling Lambda expressions in Java 6, 7, and therefore in Android too, is easy with the retrolambda library. Retrolambda transforms your Java 8 compiled bytecode so that it can run on older Java runtime versions. This code can then be run without any additional dependencies.

To use retrolambda in your Android Studio project, add the following lines to the project-level build.gradle file so that it looks like this:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        classpath 'me.tatarka:gradle-retrolambda:3.2.5'
    }
}
...

The module-level build.gradle file should contain the following highlighted lines:
apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.1"

    defaultConfig {
        applicationId "com.example.lambdas"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

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

By following these steps, you have successfully enabled first of the many Java 8 features in Android.

Method references

Method references can be conveniently used together with lambda expressions to simplify the syntax even more. For example if the body of a lambda expression only consists of a class method call, it can be replaced with a method reference like this:

Arrays.sort(new Integer[] {1, 2, 3},
    (first, second) -> first.compareTo(second));

Arrays.sort(new Integer[] {1, 2, 3}, Integer::compareTo);

The parameters are automatically supplied to match the method signature.

Three cases of the :: operator usage exist:

  • object::instanceMethod
  • Class::staticMethod 
  • Class::instanceMethod

To learn more about the method references and constructor references, read my post on Lambda expressions in Java 8 which also describes method references usage.

If you’ve already enabled lambda expressions with retrolambda library, method references should work for you too as this functionality is also included. If not, please refer to the previous section to include retrolambda into your project.

Stream API

Another great language feature Java 8 brought to the language was the Stream API. Streams represent an abstraction layer allowing the developer to process the underlying data in a declarative way.

Another benefit Stream API brings is parallel execution of operations upon streams. This allows the developer to process large amounts of data very efficiently without having to worrying about concurrency and thread management.

As an example, let’s have a list of numbers. We want to filter out those that are smaller than 10 and return a sorted list of the rest. With Stream API, it’s a matter of a few elegant lines of code:

List<Integer> numbers = new ArrayList<>();
numbers.addAll(Arrays.asList(1, 20, 3, 10, 20, 30, 4, 50, 80, 1, 2));

List<String> large_number = numbers.stream()
        .filter(num -> num >= 10)
        .sorted()
        .collect(Collectors.toList());

This is just a simple example of what Stream API provides. For more information on streams in Java, see my post on Stream API in Java 8.

In Android, we have two libraries that backport Stream API to chose from. Let’s have a look at each of them now.

Lightweight-Stream-API

The Lightweight-Stream-API library backports the Stream API to Java 7 and lower by rewriting the API using iterators. The library provides many of the stream operators in original Java 8 implementation plus it also includes several new ones like: sortBy, groupBy, chunkBy, sample, slidingWindow, and many more.

Including the library into your Android project is a matter of adding a single line to the dependencies in your build.gradle file:

dependencies {
  ...
  compile 'com.annimon:stream:1.1.3'
  ...
}

Because of the way the library has re-implemented the Stream API, some of the syntax is different to the original Stream implementation and also parallel execution has been omitted. For more information, refer to the library page on Github.

streamsupport

The second library backporting Stream API from Java 8 to the lower versions is streamsupport library. Compared to the Lighweight-Stream-API, the parallel execution is available as well as some Java 9 enhancements. Several other features like Functional interfaces from Java 8 or Optional pattern have been also included.

In order to use streamsupport library in your project, add the following dependencies into your build.gradle file:

dependencies {
    compile 'net.sourceforge.streamsupport:streamsupport:1.5.2'
    compile 'net.sourceforge.streamsupport:streamsupport-cfuture:1.5.2'
    compile 'net.sourceforge.streamsupport:streamsupport-atomic:1.5.2'
    compile 'net.sourceforge.streamsupport:streamsupport-flow:1.5.2'
    compile 'net.sourceforge.streamsupport:streamsupport-literal:1.5.2'
}

More information including usage examples can be found on the Github page of streamsupport library.

New Date and Time API

Working with date and time in Java prior to Java 8 has always been rather difficult. Several available APIs, each having its issues, like omitting time zone information, were historically available. To solve their problems, Java 8 brought a new date and time API into the language. You can read my post about the new date and time API to learn more about the history as well as the example usage of the new API.

ThreeTen Android Backport

The new date and time API from Java 8 hasn’t been included in the set of ported Java 8 features in Android. Luckily, there is a library called ThreeTen Android Backport which brings the new API instead.

To start using it, add the following line to your build.gradle file:

compile 'com.jakewharton.threetenabp:threetenabp:1.0.4'

Conclusion

In this post, four libraries bringing Java 8 features in Android have been introduced. With these libraries, you can use lambda expressions, method references, streams, or the new date and time API in Android without the need to migrate to the new Jack & Jill compiler toolchain while maintaining compatibility with previous versions of Android and Java.

Sources

Share this: