Java 8 in Android N Preview

Android team recently released Android N Preview with many new improvements including Java 8 support by the Jack compiler. In this blog post we’ll check what it actually means for Android developers and how to try new language features.

Disclaimer: this information is valid for 30th of March 2016, I’m sure that on the next releases Google team will add some more Java 8 features which are not observed here.
Image by Android Police

See the bigger picture

In this blog post it won’t make sense to introduce the new features of Oracle Java 8 — a lot of information is already available in the Internet. My personal favourite is “55 New Features in Java SE 8” by Simon Ritter.

On the other hand, the official Java 8 announcement for Android leaves some open questions for developers and sounds like the original Java 8 functionality could be not always available for us. More detailed technical announcement confirmed that. We can classify availability of Java 8 Language features as the following:

Android Gingerbread (API 9) and above:

Android N and above:

So the developer should be really selective with the relevance between Java 8 features and minSdkVersion used. Also we should note that the language backward compatibility is provided by Jack compiler. Conceptually, the Jack compiler consolidates the functionality of javac, ProGuard, and dex in a single conversion step. It means that there is no intermediate Java bytecode available and tools like JaCoCo and Mockito won’t work, the same is valid for DexGuard (enterprise version of ProGuard). Let’s hope that it is still an early preview and these issues will be fixed in the future.

Lambda expressions and related function utility APIs — here is a thing every Android developer will like. This sort of feature will be extremely useful to increase code readability — it replaces anonymous inner classes when providing event listeners. Previously it wasn’t available without extra tools or Android Studio editor folding the code.

Default and static interface methods could help us to decrease amount of extra classes for utilities, but obviously it is not the most demanded feature ever. Some other added functionality I’d call rather specific and thus took out of scope for this post.

The most interesting thing for me — Java 8 Streams — is not available in the current preview. We can find that actually it has been just merged to AOSP sources, so looking forward to see it in the next N Preview or Beta release. If you are really don’t want to wait exploring Streams — try to use Lightweight-Stream-API open-source backport for now. Update: Streams API became available in API24.

Example project

The official manual provides instructions and even a diagram how to configure your project to work with Android N Preview and Java 8. Nothing to add here, just go with the flow.

The next step is to setup you app module build.gradle file. Below you can see the example build.gradle file. From the N SDK announcement above it seems to be possible to use minSdkVersion for Jelly Bean or KitKat. Buut… with Android N Preview targetSdkVersion it won’t work on devices with API lower than N. Moreover, if you set minSdkVersion value to 23 and lower — Java 8 code won’t compile. Here are some hacks on SO forums describing how to set minSdk to the intended value and make app work. I hope you won’t do that for a production code :)

I’ve decided to keep the example below clean and haven’t added any hacks for a lower version compatibility, feel free to do it on your own or just enjoy N test devices/emulators. Update: SDK versions set to newly released production ones.

android {
compileSdkVersion 25
buildToolsVersion '25.0.2'

defaultConfig {
applicationId "org.sergiiz.thermometer"
minSdkVersion 24
targetSdkVersion 25
versionCode 1
versionName "1.0"
jackOptions{
enabled true
}
}
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
//...
}

Please note that this configuration follows new docs with updated Gradle DSL method jackOptions to setup Jack compiler config, in the older versions we were using useJack true to reach the same result.

So let’s implement some Java 8 elegant code into our good old Thermometer project.

Here is an interface, which contains the default method:

interface Thermometer {

void setCelsius(final float celsiusValue);

float getValue();

String getSign();

default String getFormattedValue(){
return String.format(Locale.getDefault(),
"The temperature is %.2f %s", getValue(), getSign());
}
}

Class which implements this interface:

class FahrenheitThermometer implements Thermometer {

private float fahrenheitDeg;

FahrenheitThermometer(float celsius) {
setCelsius(celsius);
}

@Override
public void setCelsius(float celsius) {
fahrenheitDeg = celsius * 9 / 5 + 32f;
}

@Override
public float getValue() {
return fahrenheitDeg;
}

@Override
public String getSign() {
return Constants.DEGREE + "F";
}
}

And a lambda function for click events:

buttonFahrenheit.setOnClickListener(view1 -> {
fahrenheitThermometer.setCelsius(currentCelsius);
String text = fahrenheitThermometer.getFormattedValue();
makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
});

The full source of example you can find at GitHub repository.

Conclusion

In this post we saw use-cases of Java 8 and the current state of its implementation in Android N Preview SDK. We saw limitations of the existing Jack compiler functionality that may be fixed before the final release. In the demo project we checked how to use new Java 8 features and for which target SDKs they can be applied.

Update 15-Mar-2017: Google has announced deprecation of Jack toolchain and support for Java 8 language features directly into the current javac and dx set of tools.