Java - Получает ли функция параметр внутренне при использовании ::?

У меня некоторая путаница, и я хочу прояснить свою концепцию.

Допустим, мы следующее утверждение:

.map(i -> Tests.doubleIt(i))

Итак, при использовании :: как:

.map(Tests::doubleIt)

Итак, параметр i внутренне принимается doubleIt и внутренне передается методу doubleIt?

Можем ли мы узнать внутреннее устройство, как i принимается и передается методу doubleIt в случае ::?

Я не совсем понимаю, что вы имеете в виду под «полученным внутри страны». Но map ожидает ввода точно аргумента один и возврата определенного типа. Записывая Tests::doubleIt, компилятор ищет метод с именем doubleIt в Tests, который принимает аргумент один и возвращает определенный тип.

MC Emperor 23.12.2018 12:29
stackoverflow.com/a/20001866/7972699 прочтите это поможет
Anmol 23.12.2018 12:31
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
75
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Код в map вызывает функцию, которую вы ему передаете (doubleIt), передавая ей аргумент напрямую, который doubleIt получает в качестве своего первого формального параметра. Напротив, с вашей лямбда-версией map вызывает вашу лямбда с аргументом, который ваша лямбда получает в качестве параметра i, а затем ваша лямбда вызывает doubleIt, используя i в качестве аргумента. Так что это более прямая ссылка на метод (теоретически), чем с лямбдой.

Что, если у нас есть несколько параметров?

user10796624 23.12.2018 12:25

@ user10796624 - Точно такая же ситуация. Метод, который вы передаете, должен соответствовать тому, что ожидает map (в случае map, метод с одним формальным параметром типа int [если я не ошибаюсь]). Но если вы вызываете метод, который ожидает обратного вызова, который принимает несколько параметров, то, конечно, когда он вызывает этот метод, он передаст ему несколько аргументов, по одному для каждого параметра.

T.J. Crowder 23.12.2018 12:27

и все множественные параметры будут размещены на своих местах, например p1, p1, p3 будет doubleIt(p1,p2,p3), я прав?

user10796624 23.12.2018 12:30

@ user10796624 - Конечно. Это просто вызов метода. В этом нет ничего особенного.

T.J. Crowder 23.12.2018 12:31

So, do the i parameter is internally received by the doubleIt and internally passed to doubleIt method?

.map(i -> Tests.doubleIt(i))

строка выше читается как «если элемент представлен как i, вызовите метод doubleIt с текущим элементом в качестве ввода».

Другими словами, вы указываете, «что» должно быть сделано, а «как» это должно быть сделано - это внутренняя деталь реализации.

Can we know the internals how the i is received and passed to the doubleIt method in case of ::?

Когда вы передаете Tests::doubleIt, вы, по сути, передаете «ссылку» на метод doubleIt, и для каждого элемента источника метод map вызывает функцию doubleIt, передавая текущий элемент в качестве ввода.

Больше ничего нет.

Чтения, которые могут оказаться полезными:

И все это делается internally, не нужно делать для этого лишней работы, правда?

user10796624 23.12.2018 12:27

@ user10796624 Да, основная идея функционального программирования в JDK8 заключается в том, что пользователь указывает только «что», а «как» - это внутренняя деталь реализации.

Ousmane D. 23.12.2018 12:29

@ user10796624 пожалуйста. добавил несколько блогов, которые могут оказаться вам полезными. всего наилучшего :)

Ousmane D. 23.12.2018 12:42

Это становится проще, если рассматривать отдельно тип функционального интерфейса и само значение потока.

С одной стороны, предположим упрощенный настраиваемый класс, который содержит целое число и имеет метод map:

class MyObject {
    int value = 0;

    MyObject map(Function<Integer, Integer> f) {
        this.value = f.apply(this.value);
        return this;
    }
}

Этот класс MyObject знает элемент, который он содержит, поэтому, когда его метод map выполняется, класс знает, где найти значение, которое функция примет в качестве параметра. Грубо говоря, именно так потоки используют эту функцию.

С другой стороны, создается экземпляр Function<Integer, Integer>, который будет передан в map. Как вы указали, вы можете использовать Tests::doubleIt или i -> Tests.doubleIt(i) для передачи аргумента map (в этом случае не имеет значения, какой метод, результирующий объект Function будет вызываться таким же образом).

Я пытаюсь понять: это две разные проблемы: MyObject будет знать, как получить элементы, переданные в Function.apply, в то время как класс, вызывающий map, будет отвечать за обеспечение логики. Эта «логика» и есть экземпляр Function.

Когда вы смотрите на них по отдельности, ответ на ваш вопрос становится очевидным. Я считаю, что это поможет реализовать аналогичный код.

Другие вопросы по теме