Java-Pass-Methode als Parameter

277

Ich suche nach einer Möglichkeit, eine Methode als Referenz zu übergeben. Ich verstehe, dass Java keine Methoden als Parameter übergibt, möchte jedoch eine Alternative erhalten.

Mir wurde gesagt, dass Schnittstellen die Alternative zur Übergabe von Methoden als Parameter sind, aber ich verstehe nicht, wie eine Schnittstelle als Referenzmethode fungieren kann. Wenn ich das richtig verstehe, ist eine Schnittstelle einfach ein abstrakter Satz von Methoden, die nicht definiert sind. Ich möchte keine Schnittstelle senden, die jedes Mal definiert werden muss, da mehrere verschiedene Methoden dieselbe Methode mit denselben Parametern aufrufen können.

Was ich erreichen möchte, ist etwas Ähnliches:

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
}

aufgerufen wie:

setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
Yojimbo
quelle
Im Moment besteht meine Lösung darin, einen zusätzlichen Parameter zu übergeben und mithilfe eines Schaltergehäuses die entsprechende Methode auszuwählen. Diese Lösung eignet sich jedoch nicht für die Wiederverwendung von Code.
Siehe auch diese Antwort stackoverflow.com/a/22933032/1010868 für ähnliche Frage
Tomasz Gawel

Antworten:

233

Bearbeiten : Ab Java 8 sind Lambda-Ausdrücke eine gute Lösung, wie andere Antworten gezeigt haben. Die folgende Antwort wurde für Java 7 und früher geschrieben ...


Schauen Sie sich das Befehlsmuster an .

// NOTE: code not tested, but I believe this is valid java...
public class CommandExample 
{
    public interface Command 
    {
        public void execute(Object data);
    }

    public class PrintCommand implements Command 
    {
        public void execute(Object data) 
        {
            System.out.println(data.toString());
        }    
    }

    public static void callCommand(Command command, Object data) 
    {
        command.execute(data);
    }

    public static void main(String... args) 
    {
        callCommand(new PrintCommand(), "hello world");
    }
}

Bearbeiten: Wie Pete Kirkham betont , gibt es eine andere Möglichkeit, dies mit einem Besucher zu tun . Der Besucheransatz ist etwas acceptVisitor()komplizierter - Ihre Knoten müssen alle mit einer Methode besucherbewusst sein -, aber wenn Sie einen komplexeren Objektgraphen durchlaufen müssen, lohnt es sich, ihn zu untersuchen.

Dan Vinton
quelle
2
@ Mac - gut! Dieser taucht immer wieder in Sprachen ohne erstklassige Methoden auf, um sie de facto zu simulieren. Es lohnt sich also, sich daran zu erinnern.
Dan Vinton
7
Es ist das Besuchermuster (trennen Sie die Aktion des Iterierens über eine Sammlung von der Funktion, die auf jedes Mitglied der Sammlung angewendet wird), nicht das Befehlsmuster (kapseln Sie die Argumente für einen Methodenaufruf in ein Objekt). Sie kapseln das Argument speziell nicht ein - es wird durch den Iterationsteil des Besuchermusters bereitgestellt.
Pete Kirkham
Nein, Sie benötigen die Akzeptanzmethode nur, wenn Sie einen Besuch mit einem doppelten Versand kombinieren. Wenn Sie einen monomorphen Besucher haben, ist es genau der Code, den Sie oben haben.
Pete Kirkham
In Java 8 könnte es sich um ex.operS handeln (String :: toLowerCase, "STRING"). Siehe den schönen Artikel: studytrails.com/java/java8/…
Zon
Pete Kirkham ist richtig: Ihr Code implementiert das Besuchermuster, nicht das Befehlsmuster (und das ist gut, da es das ist, was OP benötigt). Wie Pete sagt, kapseln Sie das Argument nicht ein, also führen Sie nicht Command - Ihren Befehl aus Schnittstelle hat eine Ausführung, die einen Parameter nimmt. Wikipedia nicht. Dies ist grundlegend für die Absicht des Befehlsmusters. Im ersten Absatz heißt es: " Alle Informationen kapseln ... Diese Informationen umfassen den Methodennamen, das Objekt, dem die Methode gehört, und die Werte für die Methodenparameter ."
ToolmakerSteve
73

In Java 8 können Sie eine Methode jetzt einfacher mit Lambda-Ausdrücken und Methodenreferenzen übergeben. Zunächst einige Hintergrundinformationen: Eine funktionale Schnittstelle ist eine Schnittstelle, die nur eine abstrakte Methode enthält, obwohl sie eine beliebige Anzahl von Standardmethoden (neu in Java 8) und statischen Methoden enthalten kann. Ein Lambda-Ausdruck kann die abstrakte Methode schnell implementieren, ohne dass die unnötige Syntax erforderlich ist, wenn Sie keinen Lambda-Ausdruck verwenden.

Ohne Lambda-Ausdrücke:

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

Mit Lambda-Ausdrücken:

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

Hier ist ein Auszug aus dem Java-Tutorial zu Lambda Expressions :

Syntax von Lambda-Ausdrücken

Ein Lambda-Ausdruck besteht aus Folgendem:

  • Eine durch Kommas getrennte Liste formaler Parameter in Klammern. Die CheckPerson.test-Methode enthält einen Parameter, p, der eine Instanz der Person-Klasse darstellt.

    Hinweis : Sie können den Datentyp der Parameter in einem Lambda-Ausdruck weglassen. Außerdem können Sie die Klammern weglassen, wenn nur ein Parameter vorhanden ist. Beispielsweise ist auch der folgende Lambda-Ausdruck gültig:

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
  • Der Pfeilmarker, ->

  • Ein Body, der aus einem einzelnen Ausdruck oder einem Anweisungsblock besteht. In diesem Beispiel wird der folgende Ausdruck verwendet:

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

    Wenn Sie einen einzelnen Ausdruck angeben, wertet die Java-Laufzeit den Ausdruck aus und gibt seinen Wert zurück. Alternativ können Sie eine return-Anweisung verwenden:

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

    Eine return-Anweisung ist kein Ausdruck. In einem Lambda-Ausdruck müssen Sie Anweisungen in geschweifte Klammern ({}) setzen. Sie müssen jedoch keinen Aufruf einer ungültigen Methode in geschweifte Klammern setzen. Das Folgende ist beispielsweise ein gültiger Lambda-Ausdruck:

    email -> System.out.println(email)

Beachten Sie, dass ein Lambda-Ausdruck einer Methodendeklaration sehr ähnlich sieht. Sie können Lambda-Ausdrücke als anonyme Methoden betrachten - Methoden ohne Namen.


So können Sie eine Methode mit einem Lambda-Ausdruck "übergeben":

interface I {
    public void myMethod(Component component);
}

class A {
    public void changeColor(Component component) {
        // code here
    }

    public void changeSize(Component component) {
        // code here
    }
}
class B {
    public void setAllComponents(Component[] myComponentArray, I myMethodsInterface) {
        for(Component leaf : myComponentArray) {
            if(leaf instanceof Container) { // recursive call if Container
                Container node = (Container)leaf;
                setAllComponents(node.getComponents(), myMethodInterface);
            } // end if node
            myMethodsInterface.myMethod(leaf);
        } // end looping through components
    }
}
class C {
    A a = new A();
    B b = new B();

    public C() {
        b.setAllComponents(this.getComponents(), component -> a.changeColor(component));
        b.setAllComponents(this.getComponents(), component -> a.changeSize(component));
    }
}

Die Klasse Ckann durch die Verwendung von Methodenreferenzen wie folgt noch ein wenig verkürzt werden:

class C {
    A a = new A();
    B b = new B();

    public C() {
        b.setAllComponents(this.getComponents(), a::changeColor);
        b.setAllComponents(this.getComponents(), a::changeSize);
    }
}
Der Typ mit dem Hut
quelle
Muss Klasse A von der Schnittstelle geerbt werden?
Serob_b
1
@ Serob_b Nein. Sofern Sie es nicht als Methodenreferenz übergeben möchten (siehe ::Operator), spielt es keine Rolle, was A ist. a.changeThing(component)kann in eine beliebige Anweisung oder einen beliebigen Codeblock geändert werden, solange void zurückgegeben wird.
Der Kerl mit dem Hut
29

Verwenden Sie das java.lang.reflect.MethodObjekt und rufen Sie aufinvoke

Vinodh Ramasubramanian
quelle
12
Ich verstehe nicht warum nicht. Die Frage ist, eine Methode als Parameter zu übergeben, und dies ist eine sehr gültige Methode. Dies kann auch in eine beliebige Anzahl von hübsch aussehenden Mustern eingewickelt werden, damit es gut aussieht. Und dies ist so allgemein wie es nur geht, ohne dass spezielle Schnittstellen erforderlich sind.
Vinodh Ramasubramanian
3
Haben Sie Sicherheit in JavaScript fg eingegeben? Typensicherheit ist kein Argument.
Danubian Sailor
13
Wie ist Typensicherheit kein Argument, wenn die betreffende Sprache die Typensicherheit als eine ihrer stärksten Komponenten betrachtet? Java ist eine stark typisierte Sprache, und diese starke Typisierung ist einer der Gründe, warum Sie sie einer anderen kompilierten Sprache vorziehen würden.
Adam Parkin
21
"Die Kernreflexionsfunktion wurde ursprünglich für komponentenbasierte Tools zur Anwendungserstellung entwickelt. [...] In der Regel sollte auf Objekte in normalen Anwendungen zur Laufzeit nicht reflektiert zugegriffen werden." Punkt 53: Bevorzugen Sie Schnittstellen gegenüber Reflektion aus Effective Java Second Edition. - Das ist die Denkweise der Schöpfer von Java ;-)
Wilhem Meignan
8
Keine vertretbare Verwendung von Reflect. Ich bin entsetzt, all die positiven Stimmen zu sehen. Reflect sollte niemals als allgemeiner Programmiermechanismus verwendet werden. Verwenden Sie es nur, wenn es keine andere saubere Lösung gibt.
ToolmakerSteve
22

Seit Java 8 gibt es eine Function<T, R>Schnittstelle ( docs ) mit Methode

R apply(T t);

Sie können damit Funktionen als Parameter an andere Funktionen übergeben. T ist der Eingabetyp der Funktion, R ist der Rückgabetyp.

In Ihrem Beispiel müssen Sie eine Funktion übergeben, die den ComponentTyp als Eingabe verwendet und nichts zurückgibt Void. In diesem Fall Function<T, R>ist dies nicht die beste Wahl, da es keine Autoboxing vom Typ Void gibt. Die gesuchte Schnittstelle heißt Consumer<T>( docs ) with method

void accept(T t);

Es würde so aussehen:

public void setAllComponents(Component[] myComponentArray, Consumer<Component> myMethod) {
    for (Component leaf : myComponentArray) {
        if (leaf instanceof Container) { 
            Container node = (Container) leaf;
            setAllComponents(node.getComponents(), myMethod);
        } 
        myMethod.accept(leaf);
    } 
}

Und Sie würden es mit Methodenreferenzen aufrufen:

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

Angenommen, Sie haben die Methoden changeColor () und changeSize () in derselben Klasse definiert.


Wenn Ihre Methode mehr als einen Parameter akzeptiert, können Sie BiFunction<T, U, R>- T und U als Typen von Eingabeparametern und R als Rückgabetyp verwenden. Es gibt auch BiConsumer<T, U>(zwei Argumente, kein Rückgabetyp). Leider müssen Sie für 3 und mehr Eingabeparameter selbst eine Schnittstelle erstellen. Zum Beispiel:

public interface Function4<A, B, C, D, R> {

    R apply(A a, B b, C c, D d);
}
JakubM
quelle
19

Definieren Sie zunächst eine Schnittstelle mit der Methode, die Sie als Parameter übergeben möchten

public interface Callable {
  public void call(int param);
}

Implementieren Sie eine Klasse mit der Methode

class Test implements Callable {
  public void call(int param) {
    System.out.println( param );
  }
}

// So aufrufen

Callable cmd = new Test();

Auf diese Weise können Sie cmd als Parameter übergeben und den in der Schnittstelle definierten Methodenaufruf aufrufen

public invoke( Callable callable ) {
  callable.call( 5 );
}
Stapler
quelle
1
Möglicherweise müssen Sie keine eigene Benutzeroberfläche erstellen, da Java viele davon für Sie definiert hat: docs.oracle.com/javase/8/docs/api/java/util/function/…
slim
@slim Interessanter Punkt, wie stabil sind diese Definitionen, sollen sie wie von Ihnen vorgeschlagen üblicherweise verwendet werden oder können sie wahrscheinlich brechen?
Manuel
@slim Tatsächlich antworten die Dokumente wie folgt: "Die Schnittstellen in diesem Paket sind universelle Funktionsschnittstellen, die vom JDK verwendet werden und auch vom Benutzercode verwendet werden können."
Manuel
14

Dies gilt zwar noch nicht für Java 7 und darunter, aber ich glaube, wir sollten in die Zukunft schauen und zumindest die Änderungen erkennen , die in neuen Versionen wie Java 8 zu erwarten sind.

Diese neue Version bringt nämlich Lambdas und Methodenverweise auf Java (zusammen mit neuen APIs , die eine weitere gültige Lösung für dieses Problem darstellen. Obwohl sie noch eine Schnittstelle erfordern, werden keine neuen Objekte erstellt, und zusätzliche Klassendateien müssen Ausgabeverzeichnisse aufgrund unterschiedlicher nicht verschmutzen Handhabung durch die JVM.

Beide Geschmacksrichtungen (Lambda und Methodenreferenz) erfordern eine Schnittstelle, die mit einer einzigen Methode verfügbar ist, deren Signatur verwendet wird:

public interface NewVersionTest{
    String returnAString(Object oIn, String str);
}

Namen von Methoden spielen von nun an keine Rolle mehr. Wenn ein Lambda akzeptiert wird, ist auch eine Methodenreferenz vorhanden. Um beispielsweise unsere Unterschrift hier zu verwenden:

public static void printOutput(NewVersionTest t, Object o, String s){
    System.out.println(t.returnAString(o, s));
}

Dies ist nur ein einfacher Schnittstellenaufruf, bis das Lambda 1 übergeben wird:

public static void main(String[] args){
    printOutput( (Object oIn, String sIn) -> {
        System.out.println("Lambda reached!");
        return "lambda return";
    }
    );
}

Dies wird Folgendes ausgeben:

Lambda reached!
lambda return

Methodenreferenzen sind ähnlich. Gegeben:

public class HelperClass{
    public static String testOtherSig(Object o, String s){
        return "real static method";
    }
}

und Haupt:

public static void main(String[] args){
    printOutput(HelperClass::testOtherSig);
}

die Ausgabe wäre real static method. Methodenreferenzen können statisch, instanziell, nicht statisch mit beliebigen Instanzen und sogar Konstruktoren sein . Für den Konstruktor würde etwas Ähnliches ClassName::newverwendet.

1 Dies wird von einigen nicht als Lambda angesehen, da es Nebenwirkungen hat. Es zeigt jedoch die Verwendung von einem auf eine einfachere Art und Weise zu visualisieren.

Nanofarad
quelle
12

Als ich das letzte Mal nachgesehen habe, ist Java nicht in der Lage, von Haus aus das zu tun, was Sie wollen. Sie müssen "Workarounds" verwenden, um solche Einschränkungen zu umgehen. Aus meiner Sicht sind Schnittstellen eine Alternative, aber keine gute Alternative. Vielleicht hat dir jemand gesagt, dass das so etwas bedeutet:

public interface ComponentMethod {
  public abstract void PerfromMethod(Container c);
}

public class ChangeColor implements ComponentMethod {
  @Override
  public void PerfromMethod(Container c) {
    // do color change stuff
  }
}

public class ChangeSize implements ComponentMethod {
  @Override
  public void PerfromMethod(Container c) {
    // do color change stuff
  }
}

public void setAllComponents(Component[] myComponentArray, ComponentMethod 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.PerfromMethod(leaf);
    } //end looping through components
}

Womit Sie sich dann aufrufen würden:

setAllComponents(this.getComponents(), new ChangeColor());
setAllComponents(this.getComponents(), new ChangeSize());
user246091
quelle
6

Wenn Sie diese Methoden nicht benötigen, um etwas zurückzugeben, können Sie sie dazu bringen, ausführbare Objekte zurückzugeben.

private Runnable methodName (final int arg) {
    return (new Runnable() {
        public void run() {
          // do stuff with arg
        }
    });
}

Dann benutze es wie folgt:

private void otherMethodName (Runnable arg){
    arg.run();
}
Smig
quelle
2

Ich habe kein explizites Beispiel für die Verwendung java.util.function.Functioneiner einfachen Methode als Parameterfunktion gefunden. Hier ist ein einfaches Beispiel:

import java.util.function.Function;

public class Foo {

  private Foo(String parameter) {
    System.out.println("I'm a Foo " + parameter);
  }

  public static Foo method(final String parameter) {
    return new Foo(parameter);
  }

  private static Function parametrisedMethod(Function<String, Foo> function) {
    return function;
  }

  public static void main(String[] args) {
    parametrisedMethod(Foo::method).apply("from a method");
  }
}

Grundsätzlich haben Sie ein FooObjekt mit einem Standardkonstruktor. A method, das als Parameter von dem parametrisedMethodTyp aufgerufen wird Function<String, Foo>.

  • Function<String, Foo>bedeutet, dass die Funktion a Stringals Parameter nimmt und a zurückgibt Foo.
  • Das Foo::Methodentspricht einem Lambda wiex -> Foo.method(x);
  • parametrisedMethod(Foo::method) könnte als gesehen werden x -> parametrisedMethod(Foo.method(x))
  • Das .apply("from a method")ist grundsätzlich zu tunparametrisedMethod(Foo.method("from a method"))

Welches wird dann in der Ausgabe zurückkehren:

>> I'm a Foo from a method

Das Beispiel sollte so laufen, wie es ist. Sie können dann kompliziertere Dinge aus den obigen Antworten mit verschiedenen Klassen und Schnittstellen ausprobieren.

Sylhare
quelle
Um den Apply
1

Java hat einen Mechanismus, um Namen zu übergeben und aufzurufen. Es ist Teil des Reflexionsmechanismus. Ihre Funktion sollte zusätzliche Parameter der Klasse Method verwenden.

public void YouMethod(..... Method methodToCall, Object objWithAllMethodsToBeCalled)
{
...
Object retobj = methodToCall.invoke(objWithAllMethodsToBeCalled, arglist);
...
}
David Gruzman
quelle
1

Ich bin kein Java-Experte, aber ich löse Ihr Problem folgendermaßen:

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

Ich definiere den Parameter in meiner speziellen Schnittstelle

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

Schließlich implementiere ich die getSearchText- Methode, während ich die initialize- Methode aufrufe .

initialize(getMessageContactModelList(), new AutoCompleteCallable() {
          @Override
          public String call(Object model) throws Exception {
            return "custom string" + ((xxxModel)model.getTitle());
          }
        })
Sercan özen
quelle
Eigentlich ist es die beste Antwort und der richtige Weg, es zu tun. Verdiene mehr +1
amdev
0

Verwenden Sie das Observer-Muster (manchmal auch als Listener-Muster bezeichnet):

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()... deklariert einen anonymen Typ, der die Schnittstelle implementiert.

EricSchaefer
quelle
8
Dies ist nicht das Muster, nach dem Sie suchen.
Pete Kirkham
1
Beim Beobachtermuster geht es darum, die Fähigkeit zu abstrahieren, auf eine Änderung zu reagieren. Das OP möchte die an jedem Element in einer Sammlung ausgeführten Aktionen von dem Code abstrahieren, der über die Sammlung iteriert, die das Besuchermuster darstellt.
Pete Kirkham
Das Observer / Listener-Muster ist tatsächlich das gleiche wie das Befehlsmuster. Sie unterscheiden sich nur in der Absicht. Beim Beobachter geht es um Benachrichtigung, während der Befehl erstklassige Funktionen / Lambdas ersetzt. Der Besucher hingegen ist etwas ganz anderes. Ich glaube nicht, dass es in ein paar Sätzen erklärt werden kann, also schauen Sie bitte unter en.wikipedia.org/wiki/Visitor_pattern
EricSchaefer
0

Hier ist ein grundlegendes Beispiel:

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);
    }
}

Ausgabe:

Do println
Do print
BullyWiiPlaza
quelle
0

Ich habe hier keine Lösung gefunden, die zeigt, wie eine Methode mit daran gebundenen Parametern als Parameter einer Methode übergeben wird. Unten sehen Sie ein Beispiel dafür, wie Sie eine Methode mit bereits daran gebundenen Parameterwerten übergeben können.

  1. Schritt 1: Erstellen Sie zwei Schnittstellen, eine mit Rückgabetyp, eine ohne. Java hat ähnliche Schnittstellen, aber sie sind von geringem praktischem Nutzen, da sie das Auslösen von Ausnahmen nicht unterstützen.


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


    public interface Return {
        R run() throws Exception;
    }
  1. Beispiel, wie wir beide Schnittstellen verwenden, um den Methodenaufruf in eine Transaktion einzuschließen. Beachten Sie, dass wir die Methode mit den tatsächlichen Parametern übergeben.


    //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));

Ein weiteres Beispiel zeigt, wie eine Methode übergeben wird, die tatsächlich etwas zurückgibt



        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));
Stan Sokolov
quelle
0

Beispiel für eine Lösung mit Reflexion, übergebene Methode muss öffentlich sein

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class Program {
    int i;

    public static void main(String[] args) {
        Program   obj = new Program();    //some object

        try {
            Method method = obj.getClass().getMethod("target");
            repeatMethod( 5, obj, method );
        } 
        catch ( NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            System.out.println( e ); 
        }
    }

    static void repeatMethod (int times, Object object, Method method)
        throws IllegalAccessException, InvocationTargetException {

        for (int i=0; i<times; i++)
            method.invoke(object);
    }
    public void target() {                 //public is necessary
        System.out.println("target(): "+ ++i);
    }
}
Zemiak
quelle
0

Ich schätze die obigen Antworten, konnte aber mit der folgenden Methode das gleiche Verhalten erzielen. eine Idee, die aus Javascript-Rückrufen entlehnt wurde. Ich bin offen für Korrekturen, obwohl bisher so gut (in Produktion).

Die Idee ist, den Rückgabetyp der Funktion in der Signatur zu verwenden, was bedeutet, dass die Ausbeute statisch sein muss.

Unten finden Sie eine Funktion, die einen Prozess mit einer Zeitüberschreitung ausführt.

public static void timeoutFunction(String fnReturnVal) {

    Object p = null; // whatever object you need here

    String threadSleeptime = null;

    Config config;

    try {
        config = ConfigReader.getConfigProperties();
        threadSleeptime = config.getThreadSleepTime();

    } catch (Exception e) {
        log.error(e);
        log.error("");
        log.error("Defaulting thread sleep time to 105000 miliseconds.");
        log.error("");
        threadSleeptime = "100000";
    }

    ExecutorService executor = Executors.newCachedThreadPool();
    Callable<Object> task = new Callable<Object>() {
        public Object call() {
            // Do job here using --- fnReturnVal --- and return appropriate value
            return null;
        }
    };
    Future<Object> future = executor.submit(task);

    try {
        p = future.get(Integer.parseInt(threadSleeptime), TimeUnit.MILLISECONDS);
    } catch (Exception e) {
        log.error(e + ". The function timed out after [" + threadSleeptime
                + "] miliseconds before a response was received.");
    } finally {
        // if task has started then don't stop it
        future.cancel(false);
    }
}

private static String returnString() {
    return "hello";
}

public static void main(String[] args) {
    timeoutFunction(returnString());
}
Mwa Joe
quelle