Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Function types

Header Image

Ahoy mateys! Welcome aboard on our journey to explore the world of Java Guava. In this article, we’re going to discuss one of the fundamental concepts in Guava - Function Types.

Function Types are a key component of Guava’s functional programming utilities. They represent a single input and a single output operation that transforms an input value into an output value. In simpler terms, a function is a process that takes an input value, performs a computation on it, and returns an output value.

Guava defines several types of functions, each with a specific use case. The most commonly used ones are Function, Predicate, and Consumer types. Let’s dive into each of these types and understand their usage.

Function Types

A Function is a basic interface in Guava that represents a mathematical function. It takes an input of type T and returns an output of type R. The Function interface has a single abstract method apply(T input), which takes an input argument of type T and returns an output of type R.

Here is an example of a simple Function implementation that doubles an input value of type Integer.

Function<Integer, Integer> doubleFunction = new Function<Integer, Integer>() {
  @Override
  public Integer apply(Integer input) {
    return input * 2;
  }
};

In this example, we’re creating a Function of type Integer that takes an input Integer and returns an output Integer. The implementation of the apply method simply doubles the input value and returns the result.

Functions can be composed or chained together using Guava’s compose and andThen methods. The compose method takes a Function as an argument and returns a new Function that is the result of composing the original Function with the argument Function. The andThen method does the same thing, but in reverse order.

Here is an example of composing two Functions together:

Function<Integer, Integer> doubleFunction = new Function<Integer, Integer>() {
  @Override
  public Integer apply(Integer input) {
    return input * 2;
  }
};

Function<Integer, String> toStringFunction = new Function<Integer, String>() {
  @Override
  public String apply(Integer input) {
    return input.toString();
  }
};

Function<Integer, String> composedFunction = toStringFunction.compose(doubleFunction);

In this example, we’re creating two Functions - one that doubles an Integer input value and another that converts an Integer input value to a String. We’re then composing these two Functions together using the compose method to create a new Function that doubles an input Integer and converts the result to a String.

The resulting Function is equivalent to the following lambda expression:

Function<Integer, String> composedFunction = (Integer input) -> Integer.toString(input * 2);

Functions can also be used with Guava’s collections and other utilities to simplify common programming tasks. In the next section, we’ll explore some examples of using Function types in real-world scenarios.

Examples of using function types

Now that we’ve covered the basics of Function types in Guava, let’s look at some examples of how they can be used in real-world scenarios.

Example 1: Mapping a collection

One common use case for Function types is to transform a collection of objects from one type to another. Guava’s Lists.transform method allows you to apply a Function to each element of a List and return a new List with the transformed elements.

Here’s an example of using a Function to transform a List of Strings to a List of Integers:

List<String> stringList = ImmutableList.of("1", "2", "3", "4", "5");

Function<String, Integer> stringToIntFunction = new Function<String, Integer>() {
  @Override
  public Integer apply(String input) {
    return Integer.parseInt(input);
  }
};

List<Integer> intList = Lists.transform(stringList, stringToIntFunction);

In this example, we’re using the Lists.transform method to apply a Function that converts each element of the original List from a String to an Integer. The resulting List contains the transformed elements.

Example 2: Filtering a collection

Another common use case for Function types is to filter a collection based on some criteria. Guava’s Collections2.filter method allows you to apply a Predicate (which is another type of Function) to each element of a collection and return a new collection containing only the elements that meet the specified criteria.

Here’s an example of using a Predicate to filter a List of Strings based on whether each String contains the letter “a”:

List<String> stringList = ImmutableList.of("apple", "banana", "cherry", "date", "elderberry");

Predicate<String> containsLetterA = new Predicate<String>() {
  @Override
  public boolean apply(String input) {
    return input.contains("a");
  }
};

Collection<String> filteredList = Collections2.filter(stringList, containsLetterA);

In this example, we’re using the Collections2.filter method to apply a Predicate that checks whether each String in the original List contains the letter “a”. The resulting Collection contains only the Strings that meet this criterion.

Conclusion

Function types are a fundamental concept in Guava’s functional programming utilities. They allow you to represent a single input and a single output operation that transforms an input value into an output value. Guava provides several types of functions, including Function, Predicate, and Consumer types, each with a specific use case.

By using Function types with Guava’s collections and other utilities, you can simplify common programming tasks and make your code more expressive and readable. We hope this article has provided you with a good understanding of Function types in Guava and how to use them effectively in your own projects. Keep exploring the world of Guava and happy coding, mateys!