Skip to content

Latest commit

 

History

History
129 lines (79 loc) · 5.19 KB

lambdaj.textile

File metadata and controls

129 lines (79 loc) · 5.19 KB

Some functional programming techniques

Play supports the Scala programming language. One great thing (but not the only one) about Scala is that it is a mixed imperative/functional language that makes it possible to solve a lot of problems in a functional way.

But now, what if you prefer keep using Java with Play? Could we bring some of the nice features of Scala to Java as well ? This section describes Play’s lambdaj support.

The main purpose of lambdaj is to partially eliminate the burden to write (often nested and poorly readable) loops while iterating over collections. From the lambdaj website:

How many times have you read or written the same two or three lines of code that frequently seem to go together, and even though they operate on different objects, feel like the same thing? And how often these repetitions involve some sort of collections iteration or more generically manipulation? These repetitions in the code is something that developers eventually learn to filter out and ignore when reading code, once they figure out where the interesting parts are placed. But even if the developers get used to it, it slows them down. Code like that is clearly written for computers to execute, not for developers to read.

lambdaj is a library that makes easier to address this issue by allowing to manipulate collections in a pseudo-functional and statically typed way. In our experience to iterate over collection, especially in nested loops, is often error prone and makes the code less readable. The purpose of this library is to alleviate these problems employing some functional programming techniques but without losing the static typing of java. We impose this last constraint to make refactoring easier and safer and allow the compiler to do its job.

Let’s use lambdaj

We will start with a fresh application that displays a Car catalogue. The Car model class is:

package models;

import play.;
import play.db.jpa.
;

import javax.persistence.;
import java.util.
;

@Entity
public class Car extends Model {

public String name; public String brand; public int numberOfViews; public Date lastViewed; @Transient public double price; public Car viewed() { lastViewed = new Date(); numberOfViews++; return this; }

}

And let’s write a simple action that retrieve all these cars:

public static index() {
    List<Car> cars = Car.find().fetch();
    render(cars);
}

Now in the page it would be great to be able to order all these cars by brand, so we need to extract the brands from the car list. Let’s do it the lambdaj way:

List<String> brands = collect(cars, on(Car.class).brand);

This line will iterate over all the retrieved cars, collect all the brands and feed them to the returned list. The cool thing is that we are able to express that stuff in a pure statically-typed way.

Now we need to filter this list to remove brand duplication:

Collection<String> brands = selectDistinct(
    collect(cars, on(Car.class).brand)
);

Very easy.

Batching method calls

We want to cound each time a car has been viewed, and remember the last viewed time. As we already have the viewed() method that updates the Car objects we just need to call this method on each retrieved car. Again, let’s do it the lambdaj way:

forEach(cars).viewed();

This line will iterate over each car object of the cars list and call the viewed() method on each.

And because we modified the state of the persistent objects, we need to save them. So rewrite it as:

forEach(cars).viewed().save();

Using closures

Huh? But Java doesn’t have closures! Wait, lambdaj partially fills this omission with a feature that allows you to define, in its traditional DSL style, first-class functions with free variables.

Let’s say we have a PriceWatcher utility able to fetch in real time the price of each car.

package models;

public class PriceWatcher {

public void setPrice(Car car) { // retrieve the correct price here car.price = currentPrice; }

}

Because this data need to be in real time we don’t want store it in the database. Before displaying the car list we need to create a PriceWatcher object and ask it to resolve the current price of each car. Again, let’s do it the lambdaj way:

PriceWatcher priceWatcher = new PriceWatcher();
Car.forEach(cars); {
    of(priceWatcher).setPrice(var(Car.class));
}

We define a function with a free variable, and then ask to the Car class to call them for each element of the cars list.

The final action code

Using all these good lambdaj stuff, we can finally write the index action in a very expressive fashion:

public static void index() {
    List<Car> cars = Car.find().fetch();
// Collect brands Collection brands = selectDistinct( collect(cars, on(Car.class).brand) ); // Set all these cars viewed forEach(cars).viewed().save(); // Update the prices PriceWatcher priceWatcher = new PriceWatcher(); Car.forEach(cars); { of(priceWatcher).update(var(Car.class)); } render(cars, brands);

}