I am playing with forEach
on a List<String>
, and I'm confused about why the following line is acceptable:
policies.forEach(policy -> test.addToDatabase(policy, stats));
Since forEach
requires a Consumer
, and the Consumer
accept method only takes one argument, I don't understand why the call to addtoDatabase
is acceptable, as it takes two arguments. See below for full test code. Note that I am only playing around here to learn, so this code is not meant to be perfect or elegant.
public class ConsumerTest {
private Random random = new Random();
public static void main(String[] args) {
ConsumerTest test = new ConsumerTest();
List<String> policies = new ArrayList<>();
policies.add("11111");
policies.add("22222");
policies.add("33333");
policies.add("44444");
policies.add("55555");
Stats stats = test.new Stats();
policies.forEach(policy -> test.addToDatabase(policy, stats));
System.out.println("Success count: " + stats.getSuccessCount() + "\nFailure count: " + stats.getFailureCount());
}
private void addToDatabase(String policy, Stats stats) {
// simulate success/failure adding to DB with Random
if (random.nextBoolean()) {
stats.incrementSuccessCount();
System.out.println("Success for Policy " + policy);
} else {
stats.incrementFailureCount();
System.out.println("Failure for Policy " + policy);
}
}
class Stats {
private int successCount;
private int failureCount;
public void incrementSuccessCount() {
successCount++;
}
public void incrementFailureCount() {
failureCount++;
}
public int getSuccessCount() {
return successCount;
}
public int getFailureCount() {
return failureCount;
}
}
}
I am playing with forEach on a List of Strings, and I'm confused about why the following line is acceptable:
policies.forEach(policy -> test.addToDatabase(policy, stats));
It is. You confuse the parameter of the Iterable::forEach
with the parameters of the statements inside the lambda expression. Since the only parameter inside the Iterable::forEach
is Consumer<T>
which is nothing than an implementation of the very same anonymous class:
Consumer<String> consumer = new Consumer<>() {
@Override
public void accept(final String policy) {
test.addToDatabase(policy, stats)
}
};
policies.forEach(consumer);
It is the same as:
Consumer<String> consumer = policy -> test.addToDatabase(policy, stats);
policies.forEach(consumer);
What is inside doesn't matter - the number of passed parameters into Iterable::forEach
remains only one:
policies.forEach(policy -> {
log.info("adding to database");
test.addToDatabase(policy, stats);
log.info("added to database");
});
There is theoretically an unlimited number of statements and variables you can work with. The only condition that whatever you use inside the lambda expression must be effectively final.