With the migration to OpenJDK instead to Apache Harmony, Android is having a gradual injection to Java 8 features. This talk is focused on exploring Java 8 features added on Android, how to implement them, and which benefits we can obtain to use them.

Introduction

My name Mercedes Wyss, and I am an independent consultant from Guatemala. I’m a full stack developer, doing front and back-end Android and iOS. I’m the CTO at a start-up called Produactivity, which is based in Guatemala.

Configuring Java 8

If you want to config Java 8 features, you need to have this in your gradle file:

compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 }

This is a configuration in Android Studio 3.

In Java 8, there are full and static interface methods. Some functional programming features include lambda expressions, functional interfaces, and streams. There are also repeatable annotations, method references, and type annotations.

Lambda expressions are the base of functional programming; consider the following example:

Function: squareSum(x, y) = x^2 + y^2 Lamda: (x, y) -> x^2 + y^2

Here, there is a parameter, an arrow, and a body. An arrow is used to denote that something is happening, much like in mathematics. If you watch the arrow, you are watching functional programming.

Get more development news like this

a -> a . doSomething () ( type a ) -> { a . doSomething ();}

Lambda expressions can have zero, one, or more parameters. If there are zero parameters, you can simply use empty parenthesis.

( int a , int b ) -> { return a + b ; } ( a , b ) -> { return a + b ; } ( a , b ) -> a + b ; () -> System . out . println ( "Hello World" ); ( String s ) -> { System . out . println ( s ); } () -> 42 () -> { return 3.1415 };

The three first statements are the same but written in different ways. I can send an int a and int b, and it returns a plus b. Then, we have a send a and b and I will return that, or I can put that with the curly brackets and see it’s a single statement without a return keyword.

In some cases, we use lambda expressions in Android. Imagine this is a Runnable. I use this for my splash screens. You wait some time then open your app, and it shows the logo of your company, then passes through a login or domain name.

mHandler . postDelayed ( new Runnable () { @Override public void run () { goToLogin (); } }, 5000 );

I can change that to this:

private Runnable stopAndGoToLogin = new Runnable () { @override public void run () { goToLogin (); } } mHandler . postDelayed ( stopAndGoToLogin , 5000 );

We have a Runnable as an attributable and I will send this as a parameter.

What happens if I use functional programming instead? I can declare a Runnable just with this:

private Runnable stopAndGoToLogin = () -> goToLogin (); mHandler . postDelayed ( stopAndGoToLogin , 5000 );

I put my parenthesis because my method produces nothing, and I am saying that we will go to login.

I could also do this:

mHandler . postDelayed (() -> goToLogin (), 5000 );

How we can define a Runnable, and what is a Runnable?

A Runnable is not an object, it’s an interface. An interface defines the behavior to one object when that object implements an interface. The Runnable interface doesn’t have any implementation on the method run; it just has an interface Runnable and has public void run, parenthesis and then a semi-colon.

Sometimes you try to use the word “this” inside a run to refer to activity and it will say it’s wrong because it’s not an activity. You implement an object with Runnable and you are in an object implemented for Runnable.

Functional Interfaces

A Runnable interface is interesting in that it is a functional interface - a functional interface has only one single abstract method. I have java.lang.Runnable, but I only have the void run method. When I put just the parenthesis, the system is inferring that I am overwriting the run method. If I have two methods, I can not use functional programming with that.

Another good example is the OnClickListener in buttons. There is the declaration of the interface OnClickListener. I have a single method there, OnClickView, but have an implementation for when we decide what will happen.

//Defined in the SDK interface OnClickListener { public void onClick ( View v ); } //Used in our code mButton . setOnClickListener ( new View . OnClickListener () { @Override public void onClick ( View v ) { //Our implementation } }); //Using Lambda Expression mButton . setOnClickListener (( View v ) -> { //Our Implementation });

When I implement this new View.OnClickListener, I get the parameter View v , and I do something with it.

Predicate

Predicate is a Java functional interface for finding how to have a single method called test that returns a boolean. Usually, we make filters about what we show and we use an “if this, apply, show that.” I can do that with a predicate, but I can also write other ones more complex and use an annotation that is called functional interface.

@FunctionalInterface public Interface Check < T > { boolean test ( T a ); }

This is a Predicate, but I put the name Check with a generic T.

I put this test to see if anything happens. Imagine that I have a class animal, which allows for the naming of the species, along with the abilities like swimming and hopping.

Check < Animal > checkHop = a -> a . canHop (); print ( animals , checkHop ); Check < Animal > checkSwim = a -> a . canSwim (); print ( animals , checkSwim ); private static void print ( List < Animal > animals , Check checker ) { for ( Animal animal : animals ) { if ( checker . test ( animal )) { System . out . print ( animal + " " ); } } }

I have a list of animals, and I filter the ones that can hop, then I send it to the animal list.

We can also define functions and define what will happen, using it as attributes in our code. I made another one for check swim so I define what will happen when I write code checkSwim and I send it as a parameter.

Java 8 has an issue about what you can and cannot use. There are some features that only can be from API 24; Android Nougat.

Type Annotations

There are many annotations in our code, but usually, we are restricted to using them in methods or when I define a class or interface. In Android, there something that is called a Bin Evaluation for many interface applications where you can put annotations in your parameters to establish things such as “I will make an evaluation if this is a real ME” for example.

Using credit cards as an example, when it is entered, there is a way to know if this credit card is Visa or MasterCard. I can put an annotation that says this is a Visa credit card, and implement in my annotation and make a method that validates the number of the credit card.

Now I can put this in parameters and I can create my own.

@Documented @Retention ( CLASS ) @Target ({ MEHTOD , PARAMETER , FIELD , ANNOTATION_TYPE , PACKAGE }) public @interface NonNUll { }

In this public @Interface , when I define a simple interface, it will be used at different targets.

Other Features

Streams are a new feature in Java 8. I can create a list and use Arrays.asList, put in things.

The other interesting thing is forEach , for example animals.forEach .

I can use the sorted or filter, and the filter will just return the animals that apply.

Since the beginning with an interface, I only can have static attributes; just define which methods will be implemented by my object. Sometimes you need a default method and a static method. These two have the characteristics that we have a body so I can not only say that the object will implement this object and will use this implementation.

public interface TimeClient { //... static public ZoneId getZoneId ( string zoneString ) { try { return ZoneId . of ( zoneString ); } catch ( DateTimeException e ) { System . err . println ( "Invalid time zone: " + zoneString + "; using default time zone instead." ); return ZoneId . systemDefault (); } } default public ZonedDateTime getZonedDateTime ( String zoneString ) { return ZonedDateTime . of ( getLocalDateTime (), getZoneId ( zoneString )); } }

Here’s one that has two. A static public ZoneID, so I’ll get ZoneID. When you implement with interface TimeClient, this will not be an instance, yet with all objects, we can use the same. That default public is for any single object.

The special thing about these two kinds of methods is that we can have a body that doesn’t happen before an interface.