Mercedeswyss java8featuresonandroid cover

Java 8 Features on Android

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.

Next Up: Android Architecture Components and Realm

General link arrow white

About the content

This talk was delivered live in July 2017 at 360 AnDev. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.

Mercedes Wyss

Mercedes is a full stack mobile developer with more than 5 years of experience. At present is CTO at Produactivity; and PowerWTechnology founder. She is a technology speaker, attends at least two events per month in Guatemala and international events such as JavaOne and DevNexus. She was a JUG board member in Guatemala Java Users Group for four years. She is founder of a JDuchess chapter and a Google Community (Devs+502) in Guatemala, her target communities now, and participated on events as Women Techmakers, and have a Duke’s Choice Award.

4 design patterns for a RESTless mobile integration »

close