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
boost
andpenalizeGreen
respectively).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
transform
that 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::methodName
for a static method,objectVariable::methodName
for an instance method,ClassName::new
for a constructor.
Example (continued).
Let us assume that our methods
boost
andpenalizeGreen
above 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
transform
withboost
as 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
transform
is not necessary. Instead, we can use the native method forEach, available (among others) for any Java Collection. This method takes aConsumer
method 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); } }