I want to partially apply a legacy method to some arguments using Java 8's newly introduced function objects.
Here is the method in question:
/**
* Appends a {@code character} a couple of {@code times} to a {@code string}.
*
* @return the string with the appended characters as a StringBuilder
*/
private static StringBuilder appendChar(char character, int times, String string) {
StringBuilder strBuilder = new StringBuilder(string);
for (int i = 0; i < times; i++) {
strBuilder.append(character);
}
return strBuilder;
}
Partial function application is the ability to take a function of many parameters and apply arguments to some of the parameters to create a new function that needs only the application of the remaining arguments to produce the equivalent of applying all arguments to the original function.
In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. Given a function , we might fix (or 'bind') the first argument, producing a function of type .
Currying: A function returning another function that might return another function, but every returned function must take only one parameter at a time. Partial application: A function returning another function that might return another function, but each returned function can take several parameters.
Partial application results in a function of smaller arity; in the example above, f has an arity of 3 while partial only has an arity of 2. More importantly, a partially applied function would return the result right away upon being invoke, not another function down the currying chain.
This achieves what I wanted to do:
/*
* Pass two arguments. The created function accepts a String and
* returns a StringBuilder
*/
Function<String, StringBuilder> addEllipsis = appendToMe -> appendChar(
'.', 3, appendToMe);
/*
* Pass one argument. This creates a function that takes another two
* arguments and returns a StringBuilder
*/
BiFunction<String, Integer, StringBuilder> addBangs = (appendToMe,
times) -> appendChar('!', times, appendToMe);
// Create a function by passing one argument to another function
Function<String, StringBuilder> addOneBang = appendToMe -> addBangs
.apply(appendToMe, 1);
StringBuilder res1 = addBangs.apply("Java has gone functional", 2);
StringBuilder res2 = addOneBang.apply("Lambdas are sweet");
StringBuilder res3 = addEllipsis.apply("To be continued");
For a list of all of Java's predefined varieties of the function object have a look here.
Edit:
If you have a method with a lot of arguments, you can write your own kind of function:
/**
* Represents a function that accepts three arguments and produces a result.
* This is the three-arity specialization of {@link Function}.
*
* @param <T>
* the type of the first argument to the function
* @param <U>
* the type of the second argument to the function
* @param <V>
* the type of the third argument to the function
* @param <R>
* the type of the result of the function
*
* @see Function
*/
@FunctionalInterface
public interface TriFunction<T, U, V, R> {
R apply(T t, U u, V v);
}
Method accepting many arguments; you want to provide some of them:
private static boolean manyArgs(String str, int i, double d, float f) {
return true;
}
Here is how you use your custom function object:
/*
* Pass one of the arguments. This creates a function accepting three
* arguments.
*/
TriFunction<Integer, Double, Float, Boolean> partiallyApplied = (i, d, f) ->
manyArgs("", i, d, f);
/*
* Provide the rest of the arguments.
*/
boolean res4 = partiallyApplied.apply(2, 3.0, 4.0F);
System.out.println("No time for ceremonies: " + res4);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With