Callback method #
When a method takes another method as argument, the latter is a callback method.
Anonymous methods are often used as callback methods.
in Java #
Running example #
Example. The two following Java methods have the same structure: both modify each unit in the input list.
void boostUnits(List<Unit> units){ for(Unit unit: units){ unit.health++; } } void penalizeGreenUnits(List<Unit> units){ for(Unit unit: units){ if(unit.color.equals("green")){ unit.health--; } } }In each case, let us isolate the modification that is applied to a single unit, with a dedicated method (called
boostandpenalizeGreenrespectively).void boost(Unit unit){ unit.health++; } void penalizeGreen(Unit unit){ if(unit.color.equals("green")){ unit.health--; } }Both methods have type
Unit$\to$void, so they are instances of the functional interfaceConsumer<Unit>.This allows us to factorize our code with a method
transformthat takes as input:
- an array of units,
- a callback method with type
Consumer<Unit>,and applies the callback method to each unit in the input array.
void transform(List<Unit> units, Consumer<Unit> method){ for (Unit unit: units){ method.accept(unit); } }
Passing a callback method #
A callback method in Java can be passed as:
- a variable, or
- a method reference, or
- a lambda expression.
Method reference as a callback method #
Syntax. A Java method reference is written:
ClassName::methodNamefor a static method,objectVariable::methodNamefor an instance method,ClassName::newfor a constructor.
Example (continued).
Let us assume that our methods
boostandpenalizeGreenabove are static methods of some class calledUnitTransformer:public class UnitTransformer{ static void boost(Unit unit){ unit.health++; } static void penalizeGreen(Unit unit){ if(unit.color.equals("green")){ unit.health--; } } }We can call our method
transformwithboostas callback method:List<Unit> units = getUnits(); transform( units, UnitTransformer::boost );And similarly with
penalizeGreen:List<Unit> units = getUnits(); transform( units, UnitTransformer::penalizeGreen );
Lambda expression as a callback method #
Alternatively, instead of declaring a method boost, we can directly use a lambda expression:
Example (continued).
List<Unit> units = getUnits(); transform( units, unit -> unit.health++ );And similarly, instead of declaring a method
penalizeGreen, we can use the following lambda expression:List<Unit> units = getUnits(); transform( units, unit -> { if(unit.color.equals("green")){ unit.health-- ; } } );
Native support #
Programming languages that support anonymous methods (like Java, Python, C#, C++, JavaScript, etc.) often provide concise syntaxes to use them as callback methods.
Example(continued).
In Java, the above method
transformis not necessary. Instead, we can use the native method forEach, available (among others) for any Java Collection. This method takes aConsumermethod as input, and applies this method to each element of the collection.So the following program:
getUnits().forEach(unit -> unit.health++);is equivalent to:
transform( getUnits(), unit -> unit.health++ ); void transform(List<Unit> units, Consumer<Unit> method){ for (Unit unit: units){ method.accept(unit); } }