Метод Java Pass как параметр - PullRequest
239 голосов
/ 02 февраля 2010

Я ищу способ передать метод по ссылке. Я понимаю, что Java не передает методы в качестве параметров, однако я хотел бы получить альтернативу.

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

Что я хотел бы сделать, это примерно так:

public void setAllComponents(Component[] myComponentArray, Method myMethod) {
    for (Component leaf : myComponentArray) {
        if (leaf instanceof Container) { //recursive call if Container
            Container node = (Container) leaf;
            setAllComponents(node.getComponents(), myMethod);
        } //end if node
        myMethod(leaf);
    } //end looping through components
}

вызывается, например:

setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());

Ответы [ 15 ]

1 голос
/ 02 февраля 2010

Используйте шаблон Observer (иногда также называемый шаблоном Listener):

interface ComponentDelegate {
    void doSomething(Component component);
}

public void setAllComponents(Component[] myComponentArray, ComponentDelegate delegate) {
    // ...
    delegate.doSomething(leaf);
}

setAllComponents(this.getComponents(), new ComponentDelegate() {
                                            void doSomething(Component component) {
                                                changeColor(component); // or do directly what you want
                                            }
                                       });

new ComponentDelegate()... объявляет анонимный тип, реализующий интерфейс.

0 голосов
/ 08 февраля 2019

Я не нашел здесь никакого решения, показывающего, как передать метод с привязанными к нему параметрами в качестве параметра метода. Ниже приведен пример того, как вы можете передать метод со значениями параметров, уже привязанными к нему.

  1. Шаг 1. Создайте два интерфейса, один с типом возврата, другой без. У Java есть подобные интерфейсы, но они мало практичны, потому что они не поддерживают исключение.


    public interface Do {
    void run() throws Exception;
    }


    public interface Return {
        R run() throws Exception;
    }

  1. Пример того, как мы используем оба интерфейса для переноса вызова метода в транзакции. Обратите внимание, что мы передаем метод с фактическими параметрами.


    //example - when passed method does not return any value
    public void tx(final Do func) throws Exception {
        connectionScope.beginTransaction();
        try {
            func.run();
            connectionScope.commit();
        } catch (Exception e) {
            connectionScope.rollback();
            throw e;
        } finally {
            connectionScope.close();
        }
    }

    //Invoke code above by 
    tx(() -> api.delete(6));

Другой пример показывает, как передать метод, который на самом деле что-то возвращает



        public  R tx(final Return func) throws Exception {
    R r=null;
    connectionScope.beginTransaction();
    try {
                r=func.run();
                connectionScope.commit();
            } catch (Exception e) {
                connectionScope.rollback();
                throw e;
            } finally {
                connectionScope.close();
            }
        return r;
        }
        //Invoke code above by 
        Object x= tx(() -> api.get(id));

0 голосов
/ 06 июля 2018

Я не думаю, что лямбды предназначены для этого ... Java не является функциональным языком программирования и никогда не будет таким, мы не передаем методы в качестве параметров. При этом помните, что Java является объектно-ориентированной, и с учетом этого мы можем делать все, что захотим. Первая идея - просто передать «объект, содержащий метод» в качестве параметра. Поэтому, когда вам нужно «передать» метод, просто передайте экземпляр этого класса. Обратите внимание, что когда вы определяете метод, вы должны добавить в качестве параметра экземпляр класса, который содержит метод. Это должно работать, но это не то, что мы хотим, потому что вы не можете переопределить метод, если у вас нет доступа к коду класса, а во многих случаях это невозможно; более того, я думаю, что если кому-то нужно передать метод в качестве параметра, то это потому, что поведение метода должно быть динамичным. Я имею в виду, что программист, использующий ваши классы, должен иметь возможность выбирать, что должен возвращать метод, но не его тип. К счастью для нас, у Java есть красивое и простое решение: абстрактные классы. Вкратце, абстрактные классы используются, когда вы знаете «сигнатуру» метода », но не знаете его поведение ... Вы можете обернуть имя и тип метода в абстрактный класс и передать экземпляр этого класса как параметр для метода ... Подождите ... разве это не то же самое, что и раньше? И можете ли вы иметь экземпляр абстрактного класса? Нет и нет ... но также да ... когда вы создаете абстрактный метод вы также должны переопределить его в классе, который расширяет абстрактный класс, и из-за динамического связывания Java Java всегда (если вы не объявите это static, private и некоторые другие вещи) будет использовать переопределенную версию этого. Вот пример ... Предположим, мы хотим применить функцию к массиву чисел: поэтому, если мы хотим возвести в квадрат, ввод-вывод должен выглядеть следующим образом [1,2,3,4, ...] -> [1,4,9,16 , ...] (в функциональном языке программирования, таком как haskell, это легко сделать благодаря некоторым инструментам, таким как 'map', ...). Обратите внимание, что в квадрате чисел нет ничего особенного, мы могли бы применить любую функцию, которую хотим т. Таким образом, код должен быть примерно таким [args], f -> [f (args)]. Возвращаясь к java => функция - это просто метод, поэтому нам нужна функция, которая применяет другую функцию к массиву. В двух словах, нам нужно передать метод в качестве параметра. Вот как бы я это сделал ==>

1) ОПРЕДЕЛИТЬ РЕКЛАМНЫЙ КЛАСС ОБОРОТОВ И МЕТОД

public  abstract class Function 
{
    public abstract double f(double x);
}

2) ОПРЕДЕЛИТЬ КЛАСС С МЕТОДОМ APPLY_TO_ARRAY

public class ArrayMap 
{
public static double[] apply_to_array(double[] arr, Function fun)
{
    for(int i=0; i<arr.length;i++)
    {
        arr[i]=fun.f(arr[i]);
    }
    return arr;
}
}

3) СОЗДАЙТЕ КЛАСС ИСПЫТАНИЯ И ИМЕЙТЕ НЕКОТОРОЕ УДОВОЛЬСТВИЕ

public class Testclass extends Function
{
    public static void main(String[] args) 
    {
        double[] myarr = {1,2,3,4};
        ArrayMap.apply_to_array(myarr, new Testclass());
        for (double k : myarr)
        {
        System.out.println(k);
        }

    }

    @Override
    public double f(double x) 
    {

        return Math.log(x);
    }   
}

Обратите внимание, что нам нужно передать объект типа Function, и, поскольку Testclass расширяет класс Function, мы можем его использовать, приведение происходит автоматически.

0 голосов
/ 11 августа 2017

Я не эксперт по Java, но я решаю вашу проблему следующим образом:

@FunctionalInterface
public interface AutoCompleteCallable<T> {
  String call(T model) throws Exception;
}

Я определяю параметр в моем специальном интерфейсе

public <T> void initialize(List<T> entries, AutoCompleteCallable getSearchText) {.......
//call here
String value = getSearchText.call(item);
...
}

Наконец, я реализую метод getSearchText при вызове инициализации метода.

initialize(getMessageContactModelList(), new AutoCompleteCallable() {
          @Override
          public String call(Object model) throws Exception {
            return "custom string" + ((xxxModel)model.getTitle());
          }
        })
0 голосов
/ 30 августа 2016

Вот базовый пример:

public class TestMethodPassing
{
    private static void println()
    {
        System.out.println("Do println");
    }

    private static void print()
    {
        System.out.print("Do print");
    }

    private static void performTask(BasicFunctionalInterface functionalInterface)
    {
        functionalInterface.performTask();
    }

    @FunctionalInterface
    interface BasicFunctionalInterface
    {
        void performTask();
    }

    public static void main(String[] arguments)
    {
        performTask(TestMethodPassing::println);
        performTask(TestMethodPassing::print);
    }
}

Выход:

Do println
Do print
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...