Java 8 Language features supported in Android N: Lambdas

One of the new additions the Android N brings is support for several Java 8 language features:
Lambda expressions
Default and static interface methods, and
Repeatable annotations

In this blog post we will take a look at the lambda expressions.

Setting up development environment

In order to start using these features however, the development environment needs some adjustments. The support of Java 8 language features requires a new compiler called Jack, which currently is supported only in Android Studio 2.1. So if you want to use Java 8 language features, you need to use Android Studio 2.1.

Android documentation describes in details how to setup your development environment for Java 8 support.

Enabling support for Java 8

To enable support for Java 8 in your Android project, the build.gradle file has to be adjusted by setting the compileOptions to version 1.8 and jackOptions enabled.

android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

Lambda Expressions

Lambda expressions are a new feature included in the Java 1.8. A lambda expression basically is a block of code that can be passed around to be executed later. This, in fact, is very similar to anonymous classes. However, unlike anonymous classes, lambda expressions are succinct, as a result producing less verbose code.

Consider the following 3 examples:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.d(TAG, "Clicked.");
    }
});

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         Log.d(TAG, "Position: " + position);
         Log.d(TAG, "Id: " + id);
    }
 });

Runnable runnable = new Runnable() {
    @Override
     public void run() {
         Log.d(TAG, "From Runnable");
     }
};
new Thread(runnable).start();

Converting the above pieces of code to use lambda expressions will look like this:

button.setOnClickListener(view -> Log.d(TAG, "Clicked."));

listView.setOnItemClickListener((parent, view, position, id) -> {
     Log.d(TAG, "Position: " + position);
     Log.d(TAG, "Id: " + id); 
}

Runnable runnable = () -> Log.d(TAG, "From Runnable"); 
newThread(runnable).start(); 

 

It is clear that the code with the lambdas is shorter.  Specifically, this comes from:

– removal of class instantiation, eg.: new View.OnClickListener(),
– removal of method name, return type, and access modifier, eg.: public void onClick(View view)
– as well as removal of parameter types, eg.: only view, instead of View view.

And what is left, are the actual parameters and the method body.

Lambda Expression syntax

The basic format of a lambda expression is: a list of comma separated parameters, the “->” symbol, and the body.

param1, param2, paramN -> { // body }

1. Parameter types are optional, but they can be also specified in the expression:

// without parameter types
(parent, view, position, id) -> {
      Log.d(TAG, "Position: " + position);
      Log.d(TAG, "Id: " + title);
}

// with parameter types
(AdapterView<?> parent, View view, int position, long id) -> {
      Log.d(TAG, "Position: " + position);
      Log.d(TAG, "Id: " + title);
}

2. If the body of the method has only one line, then the curly brackets can be ommited:

// with curly brackets
(parent, view, position, id) -> { processItemClick(position); }

// without curly brackets
(parent, view, position, id) -> processItemClick(position)

3. If the expression has only one parameter, then the parenthesis around parameter can be omitted:

// with parenthesis
(view) -> Log.d(TAG, "Clicked.")

// without parenthesis
view -> Log.d(TAG, "Clicked.")

4. The return keyword is optional if the body has a single expression to return the value;

// example interface
public interface Calculator {
        int calculate(int a, int b);
}

// with return
Calculator calculator = (a, b) -> {return a + b;};

// without return
Calculator calculator = (a, b) -> a + b;

5. Lambda expression that does not take any arguments:

() -> Log.d(TAG, "From Runnable")

Functional interfaces

Lambdas are treated as instances of a special interface type called functional interface. A functional interface in fact is nothing but an interface with a single abstract method. We already saw several examples of such interfaces; Runnable, Callable, OnClickListener, OnItemClickListener are all examples of functional interfaces.

A new annotation called @FunctionalInterface was introduced to mark an interface as such.

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

The annotation is optional, but it is highly recommended; it clearly communicates the intent of the interface and it also allows the compiler to perform additional checks.

@FunctionalInterface
public interface Calculator {

    int calculate(int a, int b);

    // *** this will break compilation ***
    void print(String result);
}

@FunctionalInterface
public interface Calculator {

    int calculate(int a, int b);

    // this will NOT break the compilation,
    // because print is a default method
    default void print(String result){
        Log.d(TAG, result);
    }
}

Lambda expressions might led you to the wrong idea that they are something that is going to replace anonymous classes, and now seeing that a lambda expression can be converted from an interface with only one abstract method, you might wonder how useful is this. If this is so, then I would like to recall that a lambda expression is a mechanism that allows you to pack functionality and pass it around, in a succinct way. So no, lambdas, are not intended to replace anonymous classes.

Advertisements

One thought on “Java 8 Language features supported in Android N: Lambdas

  1. Nice introduction, but the possibility of replacing one functional interface with another – with an identical signature – would be cool to be described here as well (I. E. double colon syntax).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s