Почему метод forEach принимает лямбду, которая вызывает метод с несколькими аргументами, когда Consumer принимает только один аргумент? - PullRequest
1 голос
/ 02 апреля 2020

Я играю с forEach на List<String>, и меня смущает вопрос, почему допустима следующая строка:

policies.forEach(policy -> test.addToDatabase(policy, stats));

Поскольку для forEach требуется Consumer, а Consumer метод accept принимает только один аргумент, я не понимаю, почему вызов addtoDatabase допустим, так как он принимает два аргумента. Смотрите ниже полный тестовый код. Обратите внимание, что я только играю здесь, чтобы учиться, поэтому этот код не должен быть идеальным или элегантным.

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;
        }
    }
}

1 Ответ

3 голосов
/ 02 апреля 2020

Я играю с forEach в Списке строк, и меня смущает, почему допустима следующая строка:

policies.forEach(policy -> test.addToDatabase(policy, stats));

Это , Вы путаете параметр Iterable::forEach с параметрами операторов внутри лямбда-выражения. Поскольку единственный параметр внутри Iterable::forEach - это Consumer<T>, который является не чем иным, как реализацией того же анонимного класса:

Consumer<String> consumer = new Consumer<>() {
    @Override
    public void accept(final String policy) {
        test.addToDatabase(policy, stats)
    }
};

policies.forEach(consumer);

Это так же, как:

Consumer<String> consumer = policy -> test.addToDatabase(policy, stats);
policies.forEach(consumer);

То, что внутри, не имеет значения - количество переданных параметров в Iterable::forEach остается только одним:

policies.forEach(policy -> {
    log.info("adding to database");
    test.addToDatabase(policy, stats);
    log.info("added to database");
});

Теоретически существует неограниченное количество операторов и переменные, с которыми вы можете работать. Единственное условие, что все, что вы используете внутри лямбда-выражения, должно быть окончательно .

...