Как передать функцию в качестве параметра в Java?

Можно ли передать метод в Java-метод в качестве параметра? Если да, может ли кто-нибудь, пожалуйста, направить меня? Это не кажется тривиальным

Java 8 и выше

Используя lambda-выражения Java 8+, если у вас есть class или интерфейс только с одним методом, например:

public interface MyInterface { String doSomething(int param1, String param2); } 

то где угодно, где MyInterface используется, вы можете заменить выражение lambda:

 class MyClass { public MyInterface myInterface = (p1, p2) -> { return p2 + p1; }; } 

Например, вы можете быстро создать новый stream:

 new Thread(() -> someMethod()).start(); 

И используйте синтаксис ссылки метода, чтобы сделать его еще более чистым:

 new Thread(this::someMethod).start(); 

Без lambda-выражений эти два последних примера выглядели бы так:

 new Thread(new Runnable() { someMethod(); }).start(); 

Перед Java 8

Обычным шаблоном было бы «обернуть» его в интерфейсе, например, Callable , а затем передать в Callable:

 public T myMethod(Callable func) { return func.call(); } 

Этот шаблон известен как Command Pattern .

Имейте в виду, что вам лучше всего создать интерфейс для вашего конкретного использования. Если вы решили пойти с вызываемым, то вы заменили бы T выше на любой тип возвращаемого значения, например String.

В ответ на ваш комментарий ниже вы можете сказать:

 public int methodToPass() { // do something } public void dansMethod(int i, Callable myFunc) { // do something } 

затем назовите его, возможно, используя анонимный внутренний class:

 dansMethod(100, new Callable() { public Integer call() { return methodToPass(); } }); 

Имейте в виду, что это не «трюк». Это просто базовый концептуальный эквивалент java для указателей на функцию.

Вы можете использовать reflection Java для этого. Метод будет представлен как экземпляр java.lang.reflect.Method .

 import java.lang.reflect.Method; public class Demo { public static void main(String[] args) throws Exception{ Class[] parameterTypes = new Class[1]; parameterTypes[0] = String.class; Method method1 = Demo.class.getMethod("method1", parameterTypes); Demo demo = new Demo(); demo.method2(demo, method1, "Hello World"); } public void method1(String message) { System.out.println(message); } public void method2(Object object, Method method, String message) throws Exception { Object[] parameters = new Object[1]; parameters[0] = message; method.invoke(object, parameters); } } 

Лямбда-выражения

Чтобы добавить к отличному ответу jk. , Теперь вы можете более легко использовать метод Lambda Expressions (в Java 8). Во-первых, некоторый фон. Функциональный интерфейс – это интерфейс, который имеет один и только один абстрактный метод, хотя он может содержать любое количество стандартных методов (новых в Java 8) и статических методов. Выражение lambda может быстро реализовать абстрактный метод без всякого ненужного синтаксиса, если вы не используете выражение lambda.

Без lambda-выражений:

 obj.aMethod(new AFunctionalInterface() { @Override public boolean anotherMethod(int i) { return i == 982 } }); 

С lambda-выражениями:

 obj.aMethod(i -> i == 982); 

Вот выдержка из учебника Java по lambda-выражениям :

Синтаксис lambda-выражений

Лямбда-выражение состоит из следующего:

  • Список формальных параметров, разделенных запятыми, заключенных в круглые скобки. Метод CheckPerson.test содержит один параметр p, представляющий экземпляр classа Person.

    Примечание . Вы можете опустить тип данных параметров в выражении lambda. Кроме того, вы можете опустить круглые скобки, если есть только один параметр. Например, справедливо также следующее выражение lambda:

     p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25 
  • Значок стрелки, ->

  • Тело, состоящее из одного выражения или блока операторов. В этом примере используется следующее выражение:

     p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25 

    Если вы укажете одно выражение, то среда выполнения Java оценит выражение и затем вернет его значение. Кроме того, вы можете использовать оператор возврата:

     p -> { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; } 

    Оператор return не является выражением; в выражении lambda вы должны заключать выражения в фигурные скобки ({}). Однако вам не нужно вставлять вызов void-метода в фигурные скобки. Например, следующее действительное выражение lambda:

     email -> System.out.println(email) 

Обратите внимание, что выражение lambda выглядит очень похоже на объявление метода; вы можете рассматривать lambda-выражения как анонимные методы-методы без имени.


Вот как вы можете «передать метод» с помощью выражения lambda:

Примечание: здесь используется новый стандартный функциональный интерфейс java.util.function.IntConsumer .

 class A { public static void methodToPass(int i) { // do stuff } } 
 import java.util.function.IntConsumer; class B { public void dansMethod(int i, IntConsumer aMethod) { /* you can now call the passed method by saying aMethod.accept(i), and it will be the equivalent of saying A.methodToPass(i) */ } } 
 class C { B b = new B(); public C() { b.dansMethod(100, j -> A.methodToPass(j)); //Lambda Expression here } } 

Вышеприведенный пример можно сократить еще больше, используя оператор :: .

 public C() { b.dansMethod(100, A::methodToPass); } 

Благодаря Java 8 вам не нужно выполнять следующие шаги, чтобы передать функцию методу, для чего нужны лямбды, см . Учебник Oracle Lambda Expression . Остальная часть этого сообщения описывает то, что мы привыкли делать в плохие старые дни, чтобы реализовать эту функциональность.

Обычно вы объявляете свой метод как имеющий некоторый интерфейс с помощью одного метода, затем вы передаете объект, который реализует этот интерфейс. Например, в коллекциях commons, где у вас есть интерфейсы для Closure, Transformer и Predicate и методы, которые вы передаете им. Guava – это новая улучшенная коллекция коллекций, вы можете найти там одинаковые интерфейсы.

Так, например, в коллекциях коллекций есть org.apache.commons.collections.CollectionUtils, который имеет множество статических методов, которые принимают объекты, которые были переданы, чтобы выбрать один случайным образом, существует одна вызванная существует с этой сигнатурой:

 static boolean exists(java.util.Collection collection, Predicate predicate) 

Он принимает объект, который реализует интерфейс Predicate, что означает, что он должен иметь на нем метод, который принимает некоторый объект и возвращает логическое значение.

Поэтому я могу назвать это следующим образом:

 CollectionUtils.exists(someCollection, new Predicate() { public boolean evaluate(Object object) { return ("a".equals(object.toString()); } }); 

и он возвращает true или false в зависимости от того, содержит ли someCollection объект, для которого предикат возвращает true.

Во всяком случае, это всего лишь пример, и коллективные собрания устарели. Я просто забыл об эквиваленте в Гуаве.

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

 public Runnable foo(final int x) { return new Runnable() { public void run() { System.out.println(x); } }; } 

Вернет объект Runnable, метод run() «закрывает» переданный x , точно так же, как на любом языке, который поддерживает первоclassные функции и замыкания.

Я использовал шаблон команды, который @jk. , добавив возвращаемый тип:

 public interface Callable { public O call(I input); } 

Я знаю, что это довольно старый пост, но у меня есть еще несколько более простое решение. Вы можете создать другой class внутри и сделать его абстрактным. Затем сделайте абстрактное название метода так, как вам нравится. В исходном classе создайте метод, который принимает новый class как параметр, в этом методе вызывается абстрактный метод. Это будет выглядеть примерно так.

 public class Demo { public Demo(/.../){ } public void view(Action a){ a.preform(); } /** * The Action Class is for making the Demo * View Custom Code */ public abstract class Action { public Action(/.../){ } abstract void preform(); } } 

Теперь вы можете сделать что-то подобное, чтобы вызвать метод из classа.

 /... Demo d = new Demo; Action a = new Action() { @Override void preform() { //Custom Method Code Goes Here } }; /.../ d.view(a) 

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

Java еще не поддерживает закрытие. Но есть другие языки, такие как Scala и Groovy, которые работают в JVM и поддерживают закрытие.

  • Как использовать StringUtils в Java?
  • Несколько файлов dex определяют / BuildConfig, не могут найти причину:
  • как скачать изображение с любой веб-страницы в java
  • Изменение цвета нижней строки EditText с помощью appcompat v7
  • Программно скрыть / показать Android Soft Keyboard
  • Как импортировать com.android.internal.telephony.ITelephony в приложение Android
  • Что означает '->' (стрелка) в графе зависимостей gradleиента?
  • Получить сгенерированный идентификатор после вставки
  • тип возврата main в java
  • Android - настройка тайм-аута для AsyncTask?
  • char и int в Java
  • Interesting Posts

    Сложность времени содержит (Object o), в ArrayList объектов

    Есть ли .NET-версия TLS 1.2?

    Когда Excel решает перегрузить текст в соседние ячейки или вырезать их на границе?

    Как я могу безопасно закрыть это окно и навсегда избежать появления похожих всплывающих окон от вредоносных программ и шпионских программ от Mackeeper Zeobit?

    Создание фабрики сеансов в Hibernate 4

    Что такое «Контекст» на Android?

    Как получить выход программы Exec’ed в Inno Setup?

    Является ли компилятор GNU Java (GCJ) мертвым?

    Не удалось найти файл ‘setup.bin’

    Как определить метод, который принимает lambda в качестве параметра в Java 8?

    Пример сеанса запроса диапазона HTTP

    Настроить карту сетевого диска на Mac OS X Leopard

    finalize (), вызванный для объекта с высокой степенью достижимости в Java 8

    Какое программное обеспечение следует использовать для шифрования моего жесткого диска?

    nodejs – http.createServer, похоже, дважды звонит

    Давайте будем гением компьютера.