Chapter 1. Overview

Table of Contents

1.1. What is FunctionalJ?
1.2. Why functional programming? Why FunctionalJ?
1.3. Quick, show me some code!
1.3.1. Does at least one object meet a certain condition?
1.3.2. Do all objects meet a certain condition?
1.3.3. Which objects meet a certain condition?
1.3.4. Apply a function to a list of objects, to obtain a list of results
1.3.5. Call a function of two parameters on corresponding objects from two lists
1.4. Summary of FunctionalJ's features
1.4.1. Defining functions
1.4.2. Parameter binding / partial application
1.4.3. Function composition
1.4.4. Reflection
1.4.5. Higher-order functions
1.4.6. Tuples
1.4.7. Utilities
1.4.8. Note about exceptions

1.1. What is FunctionalJ?

Note: this chapter gives a brief overview of FunctionalJ. More detailed information is given in the later chapters of this document, starting with Chapter 4, Defining functions.

FunctionalJ is a library for functional programming in the Java language.

Simply put, within FunctionalJ, a function accepts 0 or more parameters, performs some computation, and returns a result.

This is very much like a constructor or a method, except that it is represented by a function object. This makes it easier to use functions in more ways than ordinary constructors or methods.

Starting with version 0.8, FunctionalJ is available not only in a JDK 1.4 version but also a JDK 1.5 version that uses type parameters and other JDK 1.5 features.

1.2. Why functional programming? Why FunctionalJ?

While Java is my favorite programming language, I discovered some interesting functional programming concepts when I learned the pure functional programming language Haskell (http://www.haskell.org). I still find object-oriented programming to be an excellent approach to developing code; in fact, my goal is to combine both by using functions as objects. Sometimes, using functional programming constructs can really make your code more practical.

FunctionalJ makes it easy to use these functional programming patterns in the Java language.

FunctionalJ also contains mechanisms for making the use of reflection easier. Sometimes you want to determine which method to invoke dynamically at runtime, which calls for reflection. The standard JDK mechanisms for using reflection are fairly verbose; FunctionalJ contains a dynamic reflection mechanism that is more concise. A standard reflection mechanism is also provided because it can, in some situations, have better performance.

Certain utility methods were written in the course of developing the library, and were made public in utility classes since they seemed to be convenient for general use.

Finally, my goal with FunctionalJ is to provide a library that is practical. For example, the only exception that is thrown in the library is an unchecked exception, so that you have the option of handling it or not. Also, I did my best to handle null values without throwing a NullPointerException, and to always return non-null values, to eliminate as many checks for nulls in client code. Of course, where a null value is unacceptable, an exception is still thrown.

1.3. Quick, show me some code!

Note: the examples in this section use reflection, but you do not have to use reflection in order to use FunctionalJ. You can also define functions by implementing an interface or subclassing a base class. See the following section of this chapter as well as Chapter 4, Defining functions for more information.

Here are some sample situations where you may prefer functional programming constructs instead of procedural ones.

1.3.1. Does at least one object meet a certain condition?

Instead of:

boolean result = false;
for (Iterator iter = list.iterator(); iter.hasNext();)
{
    SomeClass next = (SomeClass) iter.next();
    if (next.isValid())
    {
        result = true;
        break;
    }
}
You can use:
DynReflect reflect = new JdkDynReflect();
Function1 f = reflect.instanceFunction(SomeClass.class, "valid").f1();
return Functions.any(f, list);

1.3.2. Do all objects meet a certain condition?

Instead of:

boolean result = true;
for (Iterator iter = list.iterator(); iter.hasNext();)
{
    SomeClass next = (SomeClass) iter.next();
    if (!next.isValid())
    {
        result = false;
        break;
    }
}
You can use:
Function1 f = reflect.instanceFunction(SomeClass.class, "valid").f1();
boolean result = Functions.all(f, list);

1.3.3. Which objects meet a certain condition?

Instead of:

List keep = new ArrayList();
for (Iterator iter = list.iterator(); iter.hasNext();)
{
    SomeClass next = (SomeClass) iter.next();
    if (next.isValid())
    {
        keep.add(next);
    }
}
You can use:
Function1 f = reflect.instanceFunction(SomeClass.class, "valid").f1();
List keep = Functions.filter(f, list);

1.3.4.  Apply a function to a list of objects, to obtain a list of results

Instead of:

List original = ...; // list of positive and negative Integers
List positive = new ArrayList();
for (Iterator iter = original.iterator(); iter.hasNext();)
{
    Integer next = (Integer) iter.next();
    Integer pos = new Integer(Math.min(0, next.intValue()));
    positive.add(pos);
}
You can use:
List original = ...; // list of positive and negative Integers
Function1 f = reflect.staticFunction(Math.class, "min").f2().bind(new Integer(0));
List positive = Functions.map(f, original);

1.3.5.  Call a function of two parameters on corresponding objects from two lists

Instead of:

List results = new ArrayList();
int size1 = list1 == null ? 0 : list1.size();
int size2 = list2 == null ? 0 : list2.size();
for (int i = 0, t = Math.min(size1, size2); i < t; i++)
{
    results.add(SomeClass.someMethod(list1.get(i), list2.get(i));
}
You can use:
Function2 f = reflect.staticFunction(SomeClass.class, "someMethod").f2();
List results = Tuples.zipWith(f, list1, list2);

1.4. Summary of FunctionalJ's features

1.4.1. Defining functions

Functions are defined using interfaces, according to the number of parameters accepted by the function. Interfaces are defined for functions that accept 0 to 4 parameters, as well as an arbitrary number of parameters. For the JDK 1.5 version, you can also use generic types for the function's result and parameters:

  • Function0<R>
  • Function1<R,P1>
  • Function2<R,P1,P2>
  • Function3<R,P1,P2,P3>
  • Function4<R,P1,P2,P3,P4>
  • FunctionN<R>
The type of the result is first, followed by the types of the parameters. An easy way to remember this is to notice that this order is the same as when you declare an ordinary method:

public ReturnType method(ParameterType parameter, ...)

All of the FunctionX interfaces contain a call() method, with the appropriate parameters, which calls the function and returns the result. All of the interfaces except Function0 also contain other methods; see the Javadocs for more details.

To make it easy to define a function, there are abstract base classes that implement all methods of the function interfaces except for the call() method. These classes have the Impl suffix. For example:

// function that returns a Boolean, expects 2 parameters, of type Integer
// and String
Function2<Boolean,Integer,String> isLongerThan =
    new Function2Impl<Boolean,Integer,String>()
    {
        // The types below are in the same order as in the above declaration
        public Boolean call(Integer p_length, String p_string)
        {
            return p_string.length() > p_length;
        }
    };
assertTrue(isLongerThan.call(2, "ABCDE"));

1.4.2. Parameter binding / partial application

You can bind parameters to a function without calling it, which will return a new function with those parameters being bound. Thus the new function will be a function of less parameters than the original function. When you bind a number of parameters that is less than the number of parameters expected by the function, this is also known as partial application.

Each function interface has a bind method to bind a parameter and obtain a function of one less parameter than the original function. For functions of more than one parameter, you can also bind the parameter at any position. For example:

Function2<Integer,Integer,Integer> multiply = Operators.multiply;
Function1<Integer,Integer> triple = multiply.bind(3);
assertEquals(triple.call(9), new Integer(27));

Function2<Integer,Integer,Integer> subtract = Operators.subtract;
Function1<Integer,Integer> minus4 = subtract.bind2(4);
assertEquals(minus4.call(5), new Integer(1));

1.4.3. Function composition

A function of 1 parameter f can be composed with another function g to obtain a new function h, where h(x) = f(g(x)). There are compose methods in the Function1 interface to support this. For example:

List<String> strings = Arrays.asList("  AbCd ", "a", " EF  ", "   5");

DynReflect reflect = new JdkDynReflect();
Function1<String,String> lowerTrim =
    reflect.instanceFunction(String.class, "trim").f1().compose(
        reflect.instanceFunction(String.class, "toLowerCase")
    ).f1();

List<String> result = Functions.map(lowerTrim, strings);
assertEquals(result, Arrays.asList("abcd", "a", "ef", "5"));
See Section 4.3, “Function composition” for more information.

1.4.4. Reflection

Besides defining functions by subclassing a base class or implementing an interface, FunctionalJ also provides mechanisms that use reflection to define a function that refers to an existing constructor or a method.

There are two interfaces that define obtaining functions using reflection: the standard reflection interface and the dynamic reflection interface:

  • StdReflect
  • DynReflect
The difference between the two is that the standard reflection mechanism requires specifying the types of the parameters of the reflected constructor or method, while the dynamic reflection mechanism does not. The tradeoff is that specifying the types of the parameters targets exactly one constructor or method, improving performance. On the other hand, not having to specify the parameters is more concise and more flexible.

Here is an example of obtaining a function that corresponds to the static method String.valueOf(Object):

DynReflect reflect = new JdkDynReflect();
FunctionN<String> valueOf = reflect.staticFunction(String.class, "valueOf");
assertEquals(valueOf.call(Arrays.asList(1, 2)), "[1, 2]");

1.4.5. Higher-order functions

Higher-order functions are functions that accept other functions as parameters, or return functions as a result. In FunctionalJ, higher-order functions are defined as static methods in the Functions class.

The Functions class contains methods for mapping, filtering, scanning and folding. Mapping consists of calling a 1-parameter function on a list of parameters to obtain a list of results. Filtering uses a 1-parameter function that returns a boolean result to obtain, from a list of parameters, those for which the function returns true. Scanning uses a 2-parameter function, a starting parameter, and a list of parameters to return successive results of calling the function with the previous result and the next parameter. Folding is similar to scanning, but only returns the last result.

Here is an example of mapping:

Function1<Integer,String> length = new Function1Impl<Integer,String>()
{
  public Integer call(String p_string)
  {
      return Strings.length(p_string);
  }
};
List<String> strings = Arrays.asList("A", "bb", null, "a b c d e");
List<Integer> lengths = Functions.map(length, strings);
assertEquals(lengths, Arrays.asList(1, 2, 0, 9));
Chapter 6, Using higher-order functions contains more information.

1.4.6. Tuples

Tuples are groups of data. FunctionalJ provides classes to form groups of two, three or four, named Pair, Triple and Quadruple respectively.

The Tuples class contains methods to work with tuples. For example, if you have two lists of objects and want to work with the corresponding pairs of objects from the two lists, you can use zip:

List<String> list1 = Arrays.asList("A", "b", "C", "d");
List<Integer> list2 = Arrays.asList(1, 2, 3, 4);
List<Pair<String,Integer>> pairs = Tuples.zip(list1, list2);
assertEquals(pairs.toString(), "[(A, 1), (b, 2), (C, 3), (d, 4)]");
The zipWith method is a generalization of zip. It successively calls a function with corresponding parameters from lists, and returns a list of the results. For example:
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
List<Integer> list2 = Arrays.asList(5, 6, 7, 8, 9);
Function2<Integer,Integer,Integer> multiply = Operators.multiply;
List<Integer> products = Tuples.zipWith(multiply, list1, list2);
assertEquals(products.toString(), "[5, 12, 21, 32]");
Note that in the above example, the lists are of unequal length. When this is the case, the zipping methods automatically ignore trailing elements.

Refer to Chapter 7, Using tuples for more details.

1.4.7. Utilities

While FunctionalJ is primarily about using functional programming patterns, it also provides some practical methods for common tasks. These methods are used by the library itself; but since they are generally useful, they are available for reuse in the classes of the util package.

Many of these methods deal with null for you to avoid getting a NullPointerException and clearing your code of checks for a null value. For example, to obtain the size of a list which may be null, considering a null list to have a size of 0, you can use Lists.sizeOf(Collection):

List list = ...; // might be null
for (int i = 0, t = Lists.sizeOf(list); i < t; i++)
{
    // ...
}
Similarily, to iterate over a collection or an array, using the : notation available in JDK 1.5, you can avoid a NullPointerException by considering a null collection or array as being empty:
Collection<String> strings = ...; // might be null
for (String string : Lists.iterable(strings))
{
  // ...
}
For more information, see Chapter 8, Utilities.

1.4.8. Note about exceptions

In FunctionalJ, generally one type of exception is used: FunctionException. Since this exception derives from RuntimeException, it is not a checked exception and it is not a strict requirement to handle it.