Какова ближайшая замена для указателя функции в Java? - PullRequest
298 голосов
/ 23 сентября 2008

У меня есть метод, который составляет около десяти строк кода. Я хочу создать больше методов, которые делают одно и то же, за исключением небольшого вычисления, которое изменит одну строку кода. Это идеальное приложение для передачи указателя на функцию для замены этой строки, но в Java нет указателей на функции. Какая моя лучшая альтернатива?

Ответы [ 21 ]

6 голосов
/ 17 декабря 2010

Библиотеки Google Guava , которые становятся очень популярными, имеют общий объект Function и Predicate , который они использовали во многих частях своего API.

4 голосов
/ 25 сентября 2008

Для меня звучит как шаблон стратегии. Проверьте fluffycat.com шаблоны Java.

4 голосов
/ 09 ноября 2011

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

Мне нужно было использовать переменный статический метод с известным вводом и известным выводом (оба double ). Итак, зная пакет метода и имя, я мог бы работать следующим образом:

java.lang.reflect.Method Function = Class.forName(String classPath).getMethod(String method, Class[] params);

для функции, которая принимает один дубль в качестве параметра.

Итак, в моей конкретной ситуации я инициализировал это с помощью

java.lang.reflect.Method Function = Class.forName("be.qan.NN.ActivationFunctions").getMethod("sigmoid", double.class);

и вызвал его позже в более сложной ситуации с

return (java.lang.Double)this.Function.invoke(null, args);

java.lang.Object[] args = new java.lang.Object[] {activity};
someOtherFunction() + 234 + (java.lang.Double)Function.invoke(null, args);

где активность - произвольное двойное значение. Я думаю о том, чтобы сделать это немного более абстрактным и обобщить, как это сделал SoftwareMonkey, но в настоящее время я достаточно доволен тем, как оно есть. Три строки кода, без классов и интерфейсов, это не так уж плохо.

4 голосов
/ 18 марта 2011

Чтобы сделать то же самое без интерфейсов для массива функций:

class NameFuncPair
{
    public String name;                // name each func
    void   f(String x) {}              // stub gets overridden
    public NameFuncPair(String myName) { this.name = myName; }
}

public class ArrayOfFunctions
{
    public static void main(String[] args)
    {
        final A a = new A();
        final B b = new B();

        NameFuncPair[] fArray = new NameFuncPair[]
        {
            new NameFuncPair("A") { @Override void f(String x) { a.g(x); } },
            new NameFuncPair("B") { @Override void f(String x) { b.h(x); } },
        };

        // Go through the whole func list and run the func named "B"
        for (NameFuncPair fInstance : fArray)
        {
            if (fInstance.name.equals("B"))
            {
                fInstance.f(fInstance.name + "(some args)");
            }
        }
    }
}

class A { void g(String args) { System.out.println(args); } }
class B { void h(String args) { System.out.println(args); } }
4 голосов
/ 28 января 2010

Одна из вещей, которые мне очень не нравятся при программировании на Java, это обратные вызовы функций. Одной из ситуаций, когда необходимость в них постоянно присутствовала, была рекурсивная обработка иерархий, когда вы хотите выполнить какое-то конкретное действие для каждого элемента. Как ходить по дереву каталогов или обрабатывать структуру данных. Минимализм внутри меня ненавидит необходимость определять интерфейс, а затем реализацию для каждого конкретного случая.

Однажды я подумал: а почему бы и нет? У нас есть указатели на метод - объект метода. С оптимизацией JIT-компиляторов рефлексивный вызов больше не влечет за собой огромных потерь производительности. И помимо, скажем, копирования файла из одного местоположения в другое, стоимость отраженного вызова метода бледнеет.

Когда я подумал об этом больше, я понял, что обратный вызов в парадигме ООП требует связывания объекта и метода вместе - введите объект Callback.

Ознакомьтесь с моим решением на основе отражений для Обратных вызовов в Java . Бесплатно для любого использования.

3 голосов
/ 12 сентября 2009

Выездной лямбдай

http://code.google.com/p/lambdaj/

и, в частности, его новая функция закрытия

http://code.google.com/p/lambdaj/wiki/Closures

и вы найдете очень удобочитаемый способ определения замыкания или указателя на функцию без создания бессмысленного интерфейса или использования некрасивых внутренних классов

3 голосов
/ 02 марта 2011

Ничего себе, почему бы просто не создать класс Delegate, который не так уж сложен, учитывая, что я уже сделал для java, и использовать его для передачи параметра, где T - тип возвращаемого значения. Извините, но, как программист на C ++ / C #, который изучает только Java, мне нужны указатели на функции, потому что они очень удобны. Если вы знакомы с любым классом, который имеет дело с информацией о методе, вы можете это сделать. В Java-библиотеках это будет java.lang.reflect.method.

Если вы всегда используете интерфейс, вы всегда должны его реализовывать. В обработке событий действительно нет лучшего способа регистрации / отмены регистрации из списка обработчиков, но для делегатов, в которых необходимо передавать функции, а не тип значения, создание класса делегата для его обработки для превосходящих интерфейс.

2 голосов
/ 07 октября 2016

Ни один из ответов по Java 8 не дал полного, связного примера, так что вот оно.

Объявите метод, который принимает «указатель функции» следующим образом:

void doCalculation(Function<Integer, String> calculation, int parameter) {
    final String result = calculation.apply(parameter);
}

Вызовите его, предоставив функции с лямбда-выражением:

doCalculation((i) -> i.toString(), 2);
1 голос
/ 23 июня 2015

До Java 8 ближайшей заменой функциональности, аналогичной указателю на функцию, был анонимный класс. Например:

Collections.sort(list, new Comparator<CustomClass>(){
    public int compare(CustomClass a, CustomClass b)
    {
        // Logic to compare objects of class CustomClass which returns int as per contract.
    }
});

Но теперь в Java 8 есть очень аккуратная альтернатива, известная как лямбда-выражение , которую можно использовать как:

list.sort((a, b) ->  { a.isBiggerThan(b) } );

, где isBiggerThan - метод в CustomClass. Мы также можем использовать ссылки на методы здесь:

list.sort(MyClass::isBiggerThan);
1 голос
/ 10 мая 2015

Начиная с Java8, вы можете использовать лямбды, которые также имеют библиотеки в официальном API SE 8.

Использование: Вам нужно использовать интерфейс только с одним абстрактным методом. Сделайте экземпляр этого (вы можете использовать один из уже предоставленных java SE 8) следующим образом:

Function<InputType, OutputType> functionname = (inputvariablename) {
... 
return outputinstance;
}

Для получения дополнительной информации ознакомьтесь с документацией: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

...