Как передать функцию в качестве параметра в Java? [дубликат]
этот вопрос уже есть ответ здесь:
метод Java Pass в качестве параметра
13 ответов
можно ли передать метод в метод Java в качестве параметра? Если да, может кто-нибудь, пожалуйста, направлять меня? Это не кажется тривиальным
8 ответов:
Java 8 и выше
использование лямбда-выражений Java 8+, Если у вас есть класс или интерфейс только с одним методом, например:
public interface MyInterface { String doSomething(int param1, String param2); }потом в любом месте, где используется MyInterface, вы можете заменить лямбда-выражение:
class MyClass { public MyInterface myInterface = (p1, p2) -> { return p2 + p1; }; }например, вы можете создать новый поток очень быстро:
new Thread(() -> someMethod()).start();и с помощью синтаксис ссылки на метод чтобы сделать его еще уборщик:
new Thread(this::someMethod).start();без лямбда-выражения, эти два последних примера будут выглядеть так:
new Thread(new Runnable() { someMethod(); }).start();Перед Java 8
общим шаблоном было бы "обернуть" его в интерфейс, например
Callable, например, тогда вы передаете в вызываемый:public T myMethod(Callable<T> func) { return func.call(); }этот шаблон известен как Команда.
имейте в виду, что вам лучше всего создать интерфейс для вашего конкретного использования. Если вы решили пойти с callable, то вы замените T выше с любым типом возвращаемого значения, которое вы ожидаете, например String.
в ответ на ваш комментарий ниже, можно сказать:
public int methodToPass() { // do something } public void dansMethod(int i, Callable<Integer> myFunc) { // do something }затем назовите его, возможно, используя анонимный внутренний класс:
dansMethod(100, new Callable<Integer>() { public Integer call() { return methodToPass(); } });имейте в виду, что это не трюк. Это просто базовый концептуальный эквивалент java для указателей функций.
для этого можно использовать отражение Java. Метод будет представлен в виде экземпляра java.ленг.отражать.Метод.
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.отличный ответ, теперь вы можете передать метод более легко с помощью Лямбда-Выражения (в Java 8). Во-первых, некоторые предпосылки. А функционального интерфейса - это интерфейс, который имеет один и только один абстрактный метод, хотя он может содержать любое число методы по умолчанию (новый в Java 8) и статические методы. Лямбда-выражение может быстро реализовать абстрактный метод, без всего ненужного синтаксиса, необходимого, если вы не используете лямбда-выражение.
без лямбда-выражений:
obj.aMethod(new AFunctionalInterface() { @Override public boolean anotherMethod(int i) { return i == 982 } });С лямбда-выражениями:
obj.aMethod(i -> i == 982);
вот отрывок из учебник Java по лямбда-выражениям:
синтаксис лямбда-выражений
лямбда-выражение состоит из следующего:
A разделенный запятыми список формальных параметров, заключенный в круглые скобки. В CheckPerson.метод испытания содержит один параметр, p, который представляет собой экземпляр класса человек.
Примечание: ты можно опустить тип данных параметров в лямбда-выражении. В кроме того, вы можете опустить скобки, если есть только один параметр. Например, также допустимо следующее лямбда-выражение:p -> p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25маркер со стрелкой ,
->тело, которое состоит из одного выражения или блока выражений. В этом примере используется следующее выражение:
p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25если вы укажете одно выражение, то среда выполнения Java вычисляет выражение и возвращает его значение. Альтернативно, вы можете использовать оператор return:
p -> { return p.getGender() == Person.Sex.MALE && p.getAge() >= 18 && p.getAge() <= 25; }оператор return не является выражением; в лямбда-выражении необходимо заключать операторы в фигурные скобки ({}). Тем не менее, у вас нет чтобы заключить вызов метода void в фигурные скобки. Например, ниже приведено допустимое лямбда-выражение:
email -> System.out.println(email)обратите внимание, что лямбда-выражение очень похоже на объявление метода ; лямбда-выражения можно рассматривать как анонимные методы-методы без имени.
вот как вы можете "передать метод", используя лямбда-выражение:
Примечание: это использует новый стандарт функциональный интерфейс,
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. Остальная часть этого поста описывает то, что нам приходилось делать в старые добрые времена, чтобы реализовать эту функциональность.
обычно вы объявляете свой метод как принимающий некоторый интерфейс с одним методом, а затем передаете объект, который реализует этот интерфейс. Пример находится в commons-collections, где у вас есть интерфейсы для замыкания, трансформатора и предиката, а также методы, в которые вы передаете их реализации. Guava-это новые улучшенные commons-коллекции, вы можете найти там эквивалентные интерфейсы.
Так, например, commons-collections имеет org.апаш.палата общин.коллекции.CollectionUtils, который имеет множество статических методов, которые принимают объекты, переданные в, чтобы выбрать один наугад, есть один называется существует с этой сигнатурой:
static boolean exists(java.util.Collection collection, Predicate predicate)Он принимает объект что реализует интерфейс предикат, который означает, что он должен иметь метод, который принимает объект и возвращает логическое значение.
Так я могу назвать это так:
CollectionUtils.exists(someCollection, new Predicate() { public boolean evaluate(Object object) { return ("a".equals(object.toString()); } });и это возвращает true или false в зависимости от того,
someCollectionсодержит объект, для которого предикат возвращает значение true.В любом случае, это всего лишь пример, и commons-collections устарел. Я просто забыл эквивалент в гуаве.
Java поддерживает закрытие просто отлично. Он просто не поддерживает функции, поэтому синтаксис, к которому вы привыкли для замыканий, гораздо более неудобен и громоздок: вы должны обернуть все в класс с помощью метода. Например,
public Runnable foo(final int x) { return new Runnable() { public void run() { System.out.println(x); } }; }вернет запускаемый объект, который
run()метод "закрывает"xпередано, как и в любом языке, который поддерживает первоклассные функции и замыкания.
я использовал шаблон команды, который @jk. упомянуто, добавив тип возврата:
public interface Callable<I, O> { public O call(I input); }
Я знаю, что это довольно старый пост, но у меня есть еще одно немного более простое решение. Вы можете создать другой класс внутри и сделать его абстрактным. Затем сделайте абстрактный метод, назовите его так, как вам нравится. В исходном классе сделать метод, который принимает новый класс в качестве параметра в этот метод вызова абстрактного метода. Это будет выглядеть примерно так.
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(); } }теперь вы можете сделать что-то вроде этого, чтобы вызвать метод из класса.
/... Demo d = new Demo; Action a = new Action() { @Override void preform() { //Custom Method Code Goes Here } }; /.../ d.view(a)Как я уже сказал Я знаю, что это старый, но этот способ, я думаю, немного легче. Надеюсь, это поможет.
Java не поддерживает (пока) закрытие. Но есть и другие языки, такие как Scala и Groovy, которые работают в JVM и поддерживают закрытие.
Comments