April 23, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

The Google Collections Library, Page 5

  • March 20, 2008
  • By Dick Wall
  • Send Email »
  • More Articles »

Sprinkle in Some Functional Flavor

Hopefully, by now you are already downloading the Google Collections Library, thinking it is the answer to happy and stress-free collections. But wait: There's more!

Although Java is not a functional language, it is possible to use functional concepts in at least a limited scope fairly easily, and these can lead to big readability and efficiency gains.

Say, for example, that you have a list of cars, and each car has a name and a price. You might want to separate out all of the expensive cars into a collection to examine in your program.

The conventional way to do this would be to loop through the collection of cars and check the price. If the price is above a certain limit, you could either perform some operation involving the car, or copy that car into a new collection of expensive cars.

The Google collections library offers another alternative—predicates.

Predicates

A predicate is a way to specify some selection criteria based on an instance of a class, and then that predicate can be used to selectively filter out matching instances of that class from a collection. Here is an example that might make it clearer:

final Predicate<Car> expensiveCar = new Predicate<Car>() {
   public boolean apply(Car car) {
      return car.price > 50000;
   }
}

List<Car> cars = Lists.newArrayList();
cars.add(new Car("Ford Taurus", 20000));
cars.add(new Car("Tesla", 90000));
cars.add(new Car("Toyota Camry", 25000));
cars.add(new Car("McClaren F1", 600000));

finalList<Car> premiumCars =
   Lists.immutableList(Iterables.filter(cars, expensiveCar));

In this example, you create a predicate called expensiveCar; it returns true if the price of the car is above 50000. The apply method of the Predicate has to be filled out with your selection criteria. This is then applied to the list of cars using Iterables.filter() (or Iterators.filter()) to create an immutable list of premiumCars (that will contain only the Tesla and the McLaren F1).

This is quite an elegant functional solution, although the Java syntax for inner classes takes away some of the punch (if you wanted to define the Predicate in-line, you would have to use the anonymous inner class syntax). There are several proposals for closures in Java 7 that would make the syntax much cleaner for this example. Anyway, although this is not a particular win in this simple case, as code gets more complex this solution can often be a lot more clean and readable than if statements in loops.

Functions

As well as predicates for filtering lists, Functions give you a way to transform elements from one collection into a whole new collection, potentially of differing types. This is like the map functionality from many functional languages.

For example:

final Function<Integer, String> nameForNumber =
   new Function<Integer, String>() {
   public String apply(Integer from) {
      return numbers.get(from);
   }
}

List<Integer> sequence =
   Lists.newArrayList(new Integer[] {1,2,3,5,3,1,4});

for (String name : Iterables.transform(sequence,
   nameForNumber)) {
   System.out.println(name);
}

The generic type signature to the new Function you are creating indicates that your function takes an Integer and converts it to a String in some fashion. The apply method conforms to these generic types, taking an Integer from value, and returning a String.

In this example, you are using the numbers BiMap you created earlier, to map the Integers to their String names. You then transform an ArrayList of Integers into their string names, using the Iterables.transform function. Very easy, very elegant.

This example illustrates the use of Functions nicely, but there is actually an easier way of doing it. The Functions class defines a number of static convenience methods that provide commonly used functions, one of these is forMap(), which takes a map and creates a function to apply that map to a collection, so in the case above you could replace the Function inner class definition with:

Function<Integer, String> nameForNumber =
   Functions.forMap(numbers);

There are similar classes called Predicates and Constraints (coming up) with pre-defined convenience definitions of common predicates and constraints.

Constraints

The third functional programming concept that the library provides is Constraints. These provide extra controls over what values can be added to a collection. Constraints are undergoing a lot of change in the library at present, so rather than go into a detailed example, I will simply mention that they are there and can be used now, but that if you use them, there is a good chance you will need to update that code when upgrading to future versions of the Google Collections Library.

Status

The 0.5 version belies the maturity and reliability of this library, but it is good to remember that it is not complete yet. In particular, even though the library works with both Java 5 and Java 6, it does not yet take advantage of all Java 6 features (such as Navigable interfaces). Later versions will take advantage of the Java 6 features, but a version for Java 5 will continue to be maintained until Java 7 comes out.





Page 5 of 6



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel