Table of Contents
In version 0.7.x, there was one Function
base class and several subclasses. In version 0.8, function
interfaces are used, and abstract base implementations are
provided. Moreover, the interfaces provide stronger typing in
that the interface indicates how many parameters are expected by the function.
Instead of one general Function, there is
Function0,
Function1,
Function2,
Function3,
Function4, and
FunctionN (for an arbitrary number of parameters).
Instead of using function.addParameters(...).call();
to call a function, each interface defines a call()
method that accepts the appropriate number of parameters to call the function
directly. For instance, Function2 defines
call(Object, Object) in the JDK 1.4 version, and
call(P1, P2) in the JDK 1.5 version.
Recall that in version 0.7.x, the addParameters
method returned a new Function object, achieving
partial function application. In version 0.8, the method for
binding parameters to a function has been renamed to
bind. Each function interface defines a
bind method that accepts a parameter and returns a
function that accepts one less parameter. Thus, for example, the
bind(Object) method in the
Function3 interface returns a result of type
Function2. Also, for functions that accept more than
one parameter, there are additional bind methods for
binding more than one parameter at a time.
New in version 0.8 is the possibility to bind a parameter at a different position
than the default first position. To do so, you use a binding method that is named
with the index of the position. For example, for binding the second parameter in a
function that accepts three parameters, you would use the
bind2 method.
Also new in version 0.8 is a JDK 1.5 (or greater) version that uses type parameters. This makes it possible to declare the type of the result returned by a function, as well as the type of the parameters. When writing a method that uses a function, it is also convenient to be able to declare the type of function expected or returned by the method.
Here is a sample function definition:
// 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; } };Notice how using type parameters self-documents the function and removes the need to cast parameters. When calling the function, it also removes the need to cast the result.
Since functions are more strongly typed in version 0.8 (by number of parameters in
the JDK 1.4 version, and additionally by the types of the result and parameters in
the JDK 1.5 version), the methods of the Functions
class that accept a function as a parameter have been redefined to declare the
function interface that corresponds to the appropriate number of parameters. In the
JDK 1.5 version, this also includes the generic type parameters.
For example, the map method expects a function of 1
parameter and a collection of parameters, returning a list of results of calling the
function on each parameter. In the JDK 1.4 version, this is declared as:
public static List map(Function1 p_function1, Collection p_coll);In the JDK 1.5 version, this is declared as:
public static <R,P> List<R> map(Function1<R,P> p_function1, Collection<? extends P> p_coll);Notice how the type parameters are used to indicate that the type of elements in the list of results match the type of the result returned by the function. Also, the type of the parameters in the list must be compatible with the type of the parameter expected by the function.
For the JDK 1.5 version, tuples also use the type parameter feature. Thus you can
declare the types of the objects contained by Pair,
Triple and
Quadruple. This also removes the need to cast the
returned object when extracting it from the tuple. For example:
Pair<String,Integer> pair = new Pair<String,Integer>("A", 1); String string = pair.getFirst(); Integer integer = pair.getSecond();The methods of the
Tuples class use this feature.
For example, zipping two lists returns a list of typed pairs:
public static <A,B> List<Pair<A,B>> zip(Collection<A> p_coll1, Collection<B> p_coll2);
Version 0.7.x of FunctionalJ is primarily centered around using reflection to create
functions that refer to constructors and methods. The reflection mechanism is
implemented throughout ReflectionFunction and its
subclasses.
In version 0.8, reflection is more clearly separated from the core of the library.
Everything that concerns reflection is located in the
reflect package and its subpackages. The core of the
library has no dependence on reflection.
The reflection mechanism itself has also changed to using interfaces instead of having its implementation "hard-coded" into the library. This allows to use a different reflection mechanism if desired. Included in FunctionalJ are two implementations of the reflection mechanism: one that uses the JDK, and another that uses cglib.
New in version 0.8 is the choice between using dynamic reflection (much like what is used in version 0.7.x), or standard reflection. The main difference is that standard reflection requires the types of the parameters of the reflected constructor or method, while dynamic reflection does not. Why would you want to have to specify the types of the parameters? Because you may want the improved performance over the convenience of not having to specify the parameter types, or prefer to be more specific in your code about which constructor or method you are targetting.
Between version 0.7.x and version 0.8, certain utility methods have changed:
Functions.concat becomes
Strings.concatFunctions.intersperse becomes
Strings.intersperseFunctions.sum has been removed
Lists.head becomes
Lists.first