У меня есть метод, который составляет около десяти строк кода. Я хочу создать больше методов, которые делают одно и то же, за исключением небольшого вычисления, которое изменит одну строку кода. Это идеальное приложение для передачи указателя на функцию для замены этой строки, но в Java нет указателей на функции. Какая моя лучшая альтернатива?
java
closures
function-pointers
Билл Ящерица
источник
источник
::
Ответы:
Анонимный внутренний класс
Допустим, вы хотите передать функцию с
String
параметром, который возвращаетint
.Сначала вы должны определить интерфейс с функцией в качестве единственного члена, если вы не можете повторно использовать существующий.
Метод, который принимает указатель, просто принимает
StringFunction
экземпляр следующим образом:И будет называться так:
РЕДАКТИРОВАТЬ: В Java 8, вы могли бы назвать это с лямбда-выражением:
источник
Для каждого «указателя на функцию» я бы создал небольшой класс функторов, который реализует ваши вычисления. Определите интерфейс, который будут реализовывать все классы, и передайте экземпляры этих объектов в вашу большую функцию. Это сочетание « шаблон команды » и « шаблон стратегии ».
Пример @ sblundy хорош.
источник
Если в одной строке задано заранее определенное количество различных вычислений, использование enum - быстрый, но понятный способ реализации шаблона стратегии.
Очевидно, что объявление метода стратегии, а также ровно один экземпляр каждой реализации определены в одном классе / файле.
источник
Вам необходимо создать интерфейс, который предоставляет функции, которые вы хотите передать. например:
Затем, когда вам нужно передать функцию, вы можете реализовать этот интерфейс:
Наконец, функция map использует переданную функцию Function1 следующим образом:
Вы можете часто использовать Runnable вместо своего собственного интерфейса, если вам не нужно передавать параметры, или вы можете использовать различные другие методы, чтобы сделать подсчет параметров менее «фиксированным», но обычно это компромисс с безопасностью типов. (Или вы можете переопределить конструктор для вашего функционального объекта для передачи параметров таким образом ... Есть много подходов, и некоторые работают лучше при определенных обстоятельствах.)
источник
Ссылки на метод с использованием
::
оператораВы можете использовать ссылки метода в аргументах метода, где метод принимает функциональный интерфейс . Функциональный интерфейс - это любой интерфейс, который содержит только один абстрактный метод. (Функциональный интерфейс может содержать один или несколько стандартных методов или статических методов.)
IntBinaryOperator
это функциональный интерфейс Его абстрактный методapplyAsInt
принимает дваint
s в качестве параметров и возвращаетint
.Math.max
также принимает дваint
с и возвращаетint
. В этом примереA.method(Math::max);
makeparameter.applyAsInt
отправляет два входных значенияMath.max
и возвращает результат этогоMath.max
.В общем, вы можете использовать:
вместо того:
что сокращенно от:
Для получения дополнительной информации см. Оператор :: (двойное двоеточие) в Java 8 и Спецификация языка Java §15.13 .
источник
Вы также можете сделать это (что в некоторых РЕДКИХ случаях имеет смысл). Проблема (и это большая проблема) заключается в том, что вы теряете всю безопасность типов при использовании класса / интерфейса, и вам приходится иметь дело со случаем, когда метод не существует.
Он имеет то «преимущество», что вы можете игнорировать ограничения доступа и вызывать закрытые методы (не показано в примере, но вы можете вызывать методы, которые компилятор обычно не позволяет вам вызывать).
Опять же, это редкий случай, когда это имеет смысл, но в таких случаях это хороший инструмент.
источник
Если у вас есть только одна строка, которая отличается, вы можете добавить параметр, такой как флаг, и оператор if (flag), который вызывает одну или другую строку.
источник
Вам также может быть интересно услышать о работе над Java 7, связанной с замыканиями:
Каково текущее состояние замыканий в Java?
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures
источник
Новые функциональные интерфейсы Java 8 и ссылки на методы с использованием
::
оператора.Java 8 может поддерживать ссылки на методы (MyClass :: new) с помощью указателей « @ Functional Interface ». Нет необходимости в том же имени метода, требуется только одна и та же сигнатура метода.
Пример:
Итак, что мы имеем здесь?
ВЫ ДОЛЖНЫ ИСПОЛЬЗОВАТЬ ФУНКЦИОНАЛЬНЫЕ ИНТЕРФЕЙСЫ ТОЛЬКО ДЛЯ СЛУШАТЕЛЕЙ И ТОЛЬКО ДЛЯ ТОГО!
Потому что все другие подобные указатели на функции очень плохи для читабельности кода и для понимания. Тем не менее, прямые ссылки на методы иногда оказываются полезными, например, foreach.
Есть несколько предопределенных функциональных интерфейсов:
Для более ранних версий Java вы должны попробовать библиотеки Guava, которые имеют схожую функциональность и синтаксис, как уже упоминал Адриан Петреску.
Для дополнительных исследований посмотрите на Java 8 Cheatsheet
и спасибо Парню со Шляпой для ссылки Спецификации языка Java §15.13 .
источник
Ответ @ sblundy великолепен, но у анонимных внутренних классов есть два небольших недостатка, основной из которых состоит в том, что они, как правило, не подлежат повторному использованию, а вторичный - громоздкий синтаксис.
Приятно, что его шаблон расширяется до полных классов без каких-либо изменений в основном классе (который выполняет вычисления).
Когда вы создаете экземпляр нового класса, вы можете передать в этот класс параметры, которые могут выступать в качестве константы в вашем уравнении, поэтому, если один из ваших внутренних классов выглядит следующим образом:
но иногда вам нужен такой, который:
и, возможно, третье, что:
вместо того, чтобы создавать два анонимных внутренних класса или добавлять параметр "passthrough", вы можете создать отдельный класс ACTUAL, который вы создаете как:
Он будет просто хранить константу в классе и использовать ее в методе, указанном в интерфейсе.
Фактически, если ЗНАТЬ, что ваша функция не будет сохранена / повторно использована, вы можете сделать это:
Но неизменяемые классы безопаснее - я не могу придумать оправдания, чтобы сделать такой класс изменчивым.
Я действительно публикую это только потому, что сжимаюсь всякий раз, когда слышу анонимный внутренний класс - я видел много избыточного кода, который был «Обязательным», потому что первое, что сделал программист, это стало анонимным, когда он должен был использовать реальный класс и никогда переосмыслил свое решение.
источник
Библиотеки Google Guava , которые становятся очень популярными, имеют общий объект Function и Predicate, который они использовали во многих частях своего API.
источник
Похоже, шаблон стратегии для меня. Проверьте fluffycat.com шаблоны Java.
источник
Одна из вещей, которые мне очень не нравятся при программировании на Java - это обратные вызовы функций. Одной из ситуаций, когда необходимость в них постоянно проявлялась, была рекурсивная обработка иерархий, когда вы хотите выполнить какое-то конкретное действие для каждого элемента. Как ходить по дереву каталогов или обрабатывать структуру данных. Минимализм внутри меня ненавидит необходимость определять интерфейс, а затем реализацию для каждого конкретного случая.
Однажды я подумал: а почему бы и нет? У нас есть указатели на метод - объект метода. С оптимизацией JIT-компиляторов рефлексивный вызов больше не несет огромных потерь производительности. И помимо, скажем, копирования файла из одного местоположения в другое, стоимость отраженного вызова метода бледнеет.
Когда я больше думал об этом, я понял, что обратный вызов в парадигме ООП требует связывания объекта и метода вместе - введите объект обратного вызова.
Проверьте мое решение на основе отражения для обратных вызовов в Java . Бесплатно для любого использования.
источник
ОК, эта ветка уже достаточно старая, поэтому, скорее всего, мой ответ не поможет в этом вопросе. Но так как эта тема помогла мне найти свое решение, я все равно выложу его здесь.
Мне нужно было использовать переменный статический метод с известным вводом и известным выводом (оба double ). Итак, зная пакет метода и имя, я мог бы работать следующим образом:
для функции, которая принимает один дубль в качестве параметра.
Итак, в моей конкретной ситуации я инициализировал это с
и вызвал его позже в более сложной ситуации с
где активность - произвольное двойное значение. Я думаю о том, чтобы сделать это немного более абстрактным и обобщить, как это сделал SoftwareMonkey, но в настоящее время я достаточно доволен тем, как оно есть. Три строки кода, без классов и интерфейсов, это не так уж плохо.
источник
code
уценки, я был слишком нетерпелив и глуп, чтобы найти его ;-)Чтобы сделать то же самое без интерфейсов для массива функций:
источник
Проверьте лямбдай
http://code.google.com/p/lambdaj/
и, в частности, его новая функция закрытия
http://code.google.com/p/lambdaj/wiki/Closures
и вы найдете очень удобочитаемый способ определения замыкания или указателя на функцию без создания бессмысленного интерфейса или использования некрасивых внутренних классов
источник
Ого, почему бы просто не создать класс Delegate, который не так уж и сложен, учитывая, что я уже сделал для java, и использовать его для передачи параметра, где T - тип возвращаемого значения. Извините, но, как программист на C ++ / C #, который изучает только Java, мне нужны указатели на функции, потому что они очень удобны. Если вы знакомы с любым классом, который имеет дело с информацией о методе, вы можете это сделать. В библиотеках Java это будет java.lang.reflect.method.
Если вы всегда используете интерфейс, вы всегда должны реализовать его. В обработке событий действительно нет лучшего способа регистрации / отмены регистрации из списка обработчиков, но для делегатов, в которых необходимо передавать функции, а не тип значения, создание класса делегата для его обработки для превосходящих интерфейс.
источник
Ни один из ответов Java 8 не дал полного, связного примера, так что вот оно.
Объявите метод, который принимает «указатель на функцию» следующим образом:
Вызовите его, предоставив функции лямбда-выражение:
источник
Если кто-то изо всех сил пытается передать функцию, которая принимает один набор параметров для определения своего поведения, но другой набор параметров для выполнения, например, Схемы:
см. функцию передачи с определенным параметром поведением в Java
источник
Начиная с Java8, вы можете использовать лямбды, которые также имеют библиотеки в официальном API SE 8.
Использование: Вам нужно использовать интерфейс только с одним абстрактным методом. Сделайте экземпляр этого (вы можете использовать один из уже предоставленных java SE 8) следующим образом:
Для получения дополнительной информации ознакомьтесь с документацией: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
источник
До Java 8 ближайшей заменой функциональности, подобной указателю на функцию, был анонимный класс. Например:
Но теперь в Java 8 у нас есть очень аккуратная альтернатива, известная как лямбда-выражение , которое можно использовать как:
где isBiggerThan - метод в
CustomClass
. Мы также можем использовать ссылки на методы здесь:источник