Metoda Java Pass jako parametr

277

Szukam sposobu na przekazanie metody przez odniesienie. Rozumiem, że Java nie przekazuje metod jako parametrów, jednak chciałbym uzyskać alternatywę.

Powiedziano mi, że interfejsy są alternatywą dla przekazywania metod jako parametrów, ale nie rozumiem, jak interfejs może działać jako metoda przez odniesienie. Jeśli dobrze rozumiem, interfejs jest po prostu abstrakcyjnym zestawem metod, które nie są zdefiniowane. Nie chcę wysyłać interfejsu, który musi zostać zdefiniowany za każdym razem, ponieważ kilka różnych metod może wywoływać tę samą metodę z tymi samymi parametrami.

Chciałbym osiągnąć coś podobnego do tego:

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
}

przywołane, takie jak:

setAllComponents(this.getComponents(), changeColor());
setAllComponents(this.getComponents(), changeSize());
Yojimbo
źródło
w tej chwili moim rozwiązaniem jest przekazanie dodatkowego parametru i użycie skrzynki przełączników wewnątrz, aby wybrać odpowiednią metodę. Jednak to rozwiązanie nie pozwala na ponowne użycie kodu.
Zobacz także tę odpowiedź stackoverflow.com/a/22933032/1010868 na podobne pytanie
Tomasz Gawel

Odpowiedzi:

233

Edycja : od Java 8 wyrażenia lambda są dobrym rozwiązaniem, jak wskazały inne odpowiedzi . Poniższa odpowiedź została napisana dla Java 7 i wcześniejszych ...


Spójrz na wzór poleceń .

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

Edycja: jak zauważa Pete Kirkham , istnieje inny sposób na zrobienie tego za pomocą Odwiedzającego . Podejście oparte na odwiedzających jest nieco bardziej zaangażowane - wszystkie twoje węzły muszą być świadome acceptVisitor()metody przy pomocy odwiedzających - ale jeśli chcesz przejść przez bardziej złożony wykres obiektów, warto to zbadać.

Dan Vinton
źródło
2
@Mac - dobrze! ten pojawia się wielokrotnie w językach bez metod pierwszej klasy jako de facto sposób na ich symulację, więc warto o tym pamiętać.
Dan Vinton
7
Jest to wzorzec gościa (oddziel działanie iteracji nad kolekcją od funkcji zastosowanej do każdego elementu kolekcji), a nie wzorzec polecenia (obuduj argumenty wywołania metody w obiekcie). W szczególności argument nie jest hermetyzowany - jest on dostarczany przez iteracyjną część wzorca odwiedzającego.
Pete Kirkham,
Nie, potrzebujesz metody akceptacji tylko wtedy, gdy łączysz odwiedziny z podwójną wysyłką. Jeśli masz monomorficznego gościa, jest to dokładnie ten kod, który masz powyżej.
Pete Kirkham,
W Javie 8 może być jak ex.operS (String :: toLowerCase, „STRING”). Zobacz ładny artykuł: studytrails.com/java/java8/…
Zon
Pete Kirkham ma rację: twój kod implementuje wzorzec gościa, a nie wzorzec polecenia (i to dobrze, bo tego potrzebuje OP). Jak mówi Pete, nie ujmujesz argumentu, więc nie wykonujesz polecenia - twoje polecenie Interfejs ma wykonanie, które przyjmuje parametr. Wikipedia nie. Ma to zasadnicze znaczenie dla intencji wzorca poleceń. Jak akapit pierwszy mówi „obuduj wszystkie informacje ... Informacje te obejmują nazwę metody, obiekt będący właścicielem metody i wartości parametrów metody ”.
ToolmakerSteve
73

W Javie 8 możesz teraz łatwiej przekazać metodę za pomocą wyrażeń lambda i odwołań do metod. Po pierwsze, pewne tło: interfejs funkcjonalny to interfejs, który ma jedną i tylko jedną metodę abstrakcyjną, chociaż może zawierać dowolną liczbę metod domyślnych (nowość w Javie 8) i metod statycznych. Wyrażenie lambda może szybko zaimplementować metodę abstrakcyjną, bez całej niepotrzebnej składni potrzebnej, jeśli nie użyjesz wyrażenia lambda.

Bez wyrażeń lambda:

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

Z wyrażeniami lambda:

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

Oto fragment samouczka Java na temat wyrażeń Lambda :

Składnia wyrażeń lambda

Wyrażenie lambda składa się z następujących elementów:

  • Rozdzielona przecinkami lista parametrów formalnych zawartych w nawiasach. Metoda CheckPerson.test zawiera jeden parametr p, który reprezentuje instancję klasy Person.

    Uwaga : Możesz pominąć typ danych parametrów w wyrażeniu lambda. Ponadto można pominąć nawiasy, jeśli istnieje tylko jeden parametr. Na przykład poprawne jest również następujące wyrażenie lambda:

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
  • Token strzały, ->

  • Treść, która składa się z pojedynczego wyrażenia lub bloku instrukcji. W tym przykładzie użyto następującego wyrażenia:

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

    Jeśli określisz pojedyncze wyrażenie, środowisko wykonawcze Java ocenia to wyrażenie, a następnie zwraca jego wartość. Alternatywnie możesz użyć instrukcji return:

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

    Instrukcja return nie jest wyrażeniem; w wyrażeniu lambda musisz zawrzeć instrukcje w nawiasach klamrowych ({}). Jednak nie trzeba dołączać wywołania pustej metody w nawiasach klamrowych. Na przykład następujące wyrażenie jest poprawnym wyrażeniem lambda:

    email -> System.out.println(email)

Zauważ, że wyrażenie lambda bardzo przypomina deklarację metody; możesz traktować wyrażenia lambda jako metody anonimowe - metody bez nazwy.


Oto, w jaki sposób możesz „przekazać metodę” za pomocą wyrażenia lambda:

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

Klasę Cmożna jeszcze bardziej skrócić, korzystając z takich referencji metod:

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

    public C() {
        b.setAllComponents(this.getComponents(), a::changeColor);
        b.setAllComponents(this.getComponents(), a::changeSize);
    }
}
Facet z kapeluszem
źródło
Czy klasa A musi być dziedziczona z interfejsu?
Serob_b
1
@Serob_b Nie. O ile nie chcesz przekazać go jako odwołania do metody (patrz ::operator), nie ma znaczenia, co to jest A. a.changeThing(component)można zmienić na dowolną instrukcję lub blok kodu, o ile zwróci wartość void.
Facet z kapeluszem
29

Użyj java.lang.reflect.Methodobiektu i wywołajinvoke

Vinodh Ramasubramanian
źródło
12
Nie rozumiem dlaczego nie. Pytanie polega na podaniu metody jako parametru i jest to bardzo prawidłowy sposób jej wykonania. Można go również owinąć dowolną liczbą ładnie wyglądających wzorów, aby wyglądały dobrze. Jest to tak ogólne, jak to możliwe, bez potrzeby stosowania specjalnych interfejsów.
Vinodh Ramasubramanian
3
Czy wpisałeś bezpieczeństwo w JavaScript fg? Bezpieczeństwo typu nie jest argumentem.
Danubian Sailor
13
Jak bezpieczeństwo typu nie jest argumentem, gdy dany język traktuje bezpieczeństwo typu jako jeden z jego najsilniejszych elementów? Java jest silnie typowanym językiem, a to mocne typowanie jest jednym z powodów, dla których wybrałeś go zamiast innego skompilowanego języka.
Adam Parkin,
21
„Podstawowa funkcja odbicia została pierwotnie zaprojektowana dla narzędzi do budowania aplikacji opartych na komponentach. [...] Z reguły do ​​obiektów nie powinno się uzyskiwać dostępu odblaskowego w normalnych aplikacjach w czasie wykonywania.” Punkt 53: Wolę interfejsy od refleksji, od Effective Java Second Edition. - Taki jest tok myślenia twórców Javy ;-)
Wilhem Meignan
8
Nie jest to uzasadnione użycie refleksji. Jestem przerażony, widząc wszystkie głosy poparcia. reflect nie był nigdy przeznaczony do wykorzystania jako ogólny mechanizm programowania; używaj go tylko wtedy, gdy nie ma innego czystego rozwiązania.
ToolmakerSteve,
22

Od wersji Java 8 istnieje Function<T, R>interfejs ( dokumenty ), który ma metodę

R apply(T t);

Można go używać do przekazywania funkcji jako parametrów do innych funkcji. T jest typem wejściowym funkcji, R jest typem zwracanym.

W twoim przykładzie musisz przekazać funkcję, która pobiera Componenttyp jako dane wejściowe i nic nie zwraca - Void. W tym przypadku Function<T, R>nie jest najlepszym wyborem, ponieważ nie ma autoboxowania typu Void. Interfejs, którego szukasz, nazywa się Consumer<T>( docs ) metodą

void accept(T t);

Wyglądałoby to tak:

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

I nazwałbyś to przy użyciu referencji metod:

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

Zakładając, że zdefiniowałeś metody changeColor () i changeSize () w tej samej klasie.


Jeśli twoja metoda akceptuje więcej niż jeden parametr, możesz użyć BiFunction<T, U, R>- T i U są typami parametrów wejściowych, a R jest typem zwracanym. Są też BiConsumer<T, U>(dwa argumenty, brak typu zwracanego). Niestety dla 3 i więcej parametrów wejściowych musisz sam stworzyć interfejs. Na przykład:

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

    R apply(A a, B b, C c, D d);
}
JakubM
źródło
19

Najpierw zdefiniuj interfejs za pomocą metody, którą chcesz przekazać jako parametr

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

Zaimplementuj klasę za pomocą tej metody

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

// Wywołaj w ten sposób

Callable cmd = new Test();

Pozwala to przekazać cmd jako parametr i wywołać wywołanie metody zdefiniowane w interfejsie

public invoke( Callable callable ) {
  callable.call( 5 );
}
układacz
źródło
1
Być może nie będziesz musiał stworzyć własnego interfejsu, ponieważ java zdefiniowała wiele z nich: docs.oracle.com/javase/8/docs/api/java/util/function/…
slim
@slim Ciekawe, jak stabilne są te definicje, czy mają być używane zwyczajowo, jak sugerujesz, czy też mogą się złamać?
Manuel
@slim W rzeczywistości dokumenty odpowiadają: „Interfejsy w tym pakiecie są interfejsami funkcjonalnymi ogólnego przeznaczenia używanymi przez JDK i mogą być również używane przez kod użytkownika”.
Manuel
14

Chociaż nie jest to jeszcze ważne dla Java 7 i niższych, uważam, że powinniśmy spojrzeć w przyszłość i przynajmniej rozpoznać zmiany, które pojawią się w nowych wersjach, takich jak Java 8.

Mianowicie, ta nowa wersja wprowadza JavaDa i odwołania do metod do Javy (wraz z nowymi interfejsami API , które są kolejnym prawidłowym rozwiązaniem tego problemu. Chociaż nadal wymagają interfejsu, nie są tworzone żadne nowe obiekty, a dodatkowe pliki klas nie muszą zanieczyszczać katalogów wyjściowych z powodu różnych obsługa przez JVM.

Oba smaki (lambda i odniesienie do metody) wymagają interfejsu dostępnego za pomocą jednej metody, której sygnatura jest używana:

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

Odtąd nazwy metod nie będą miały znaczenia. Tam, gdzie lambda jest akceptowana, jest również odniesienie do metody. Na przykład, aby użyć naszego podpisu tutaj:

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

Jest to zwykłe wywołanie interfejsu, aż do przejścia lambda 1 :

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

Spowoduje to wygenerowanie:

Lambda reached!
lambda return

Odniesienia do metod są podobne. Dany:

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

i główne:

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

wynik byłby real static method. Odwołania do metod mogą być statyczne, instancja, niestatyczne z dowolnymi instancjami, a nawet konstruktorami . Dla konstruktora ClassName::newbyłoby coś podobnego .

1 Dla niektórych nie jest to lambda, ponieważ ma skutki uboczne. Ilustruje to jednak użycie jednego w prostszy do wizualizacji sposób.

nanofarad
źródło
12

Ostatnim razem, gdy sprawdzałem, Java nie jest w stanie natywnie robić tego, co chcesz; musisz obejść takie ograniczenia, używając obejść. O ile mi się wydaje, interfejsy są alternatywą, ale nie dobrą alternatywą. Być może ktokolwiek ci to powiedział:

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
}

Które następnie wywołałeś za pomocą:

setAllComponents(this.getComponents(), new ChangeColor());
setAllComponents(this.getComponents(), new ChangeSize());
użytkownik246091
źródło
6

Jeśli nie potrzebujesz tych metod, aby coś zwrócić, możesz sprawić, że zwrócą obiekty Runnable.

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

Następnie użyj go w następujący sposób:

private void otherMethodName (Runnable arg){
    arg.run();
}
Smig
źródło
2

Nie znalazłem żadnego przykładu, który byłby dla mnie wystarczająco wyraźny, jak używać java.util.function.Functionprostej metody jako funkcji parametru. Oto prosty przykład:

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

Zasadniczo masz Fooobiekt z domyślnym konstruktorem. A, methodktóry zostanie wywołany jako parametr, z parametrisedMethodktórego jest typu Function<String, Foo>.

  • Function<String, Foo>oznacza, że ​​funkcja przyjmuje Stringparametr jako i zwraca a Foo.
  • Foo::MethodOdpowiadają jak lambdax -> Foo.method(x);
  • parametrisedMethod(Foo::method) może być postrzegane jako x -> parametrisedMethod(Foo.method(x))
  • Jest .apply("from a method")to w zasadzie do zrobieniaparametrisedMethod(Foo.method("from a method"))

Który następnie zwróci w wyniku:

>> I'm a Foo from a method

Przykład powinien być uruchomiony w obecnej postaci, możesz wypróbować bardziej skomplikowane rzeczy z powyższych odpowiedzi przy użyciu różnych klas i interfejsów.

Sylhare
źródło
aby skorzystać z połączenia z aplikacją w
Androidzie
1

Java ma mechanizm przekazywania nazwy i wywoływania jej. Jest to część mechanizmu odbicia. Twoja funkcja powinna przyjąć dodatkowy parametr metody klasy.

public void YouMethod(..... Method methodToCall, Object objWithAllMethodsToBeCalled)
{
...
Object retobj = methodToCall.invoke(objWithAllMethodsToBeCalled, arglist);
...
}
David Gruzman
źródło
1

Nie jestem ekspertem od Java, ale rozwiązuję Twój problem w następujący sposób:

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

Definiuję parametr w moim specjalnym interfejsie

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

Wreszcie implementuję metodę getSearchText podczas wywoływania metody initialize .

initialize(getMessageContactModelList(), new AutoCompleteCallable() {
          @Override
          public String call(Object model) throws Exception {
            return "custom string" + ((xxxModel)model.getTitle());
          }
        })
Sercan özen
źródło
Właściwie to najlepsza odpowiedź i właściwy sposób na zrobienie tego. Zasługuje na więcej +1
amdev
0

Użyj wzorca Observer (czasami nazywanego również Wzorem Słuchacza):

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()... deklaruje anonimowy typ implementujący interfejs.

EricSchaefer
źródło
8
To nie jest wzór, którego szukasz.
Pete Kirkham
1
Wzorzec obserwatora dotyczy wyodrębnienia zdolności reagowania na zmianę. OP chce wyodrębnić akcję wykonaną na każdym elemencie w kolekcji, z dala od kodu iterującego kolekcję, który jest wzorcem użytkownika.
Pete Kirkham,
Wzorzec Observer / Listener jest w rzeczywistości taki sam jak wzorzec Command. Różnią się tylko intencją. Obserwator dotyczy powiadomień, podczas gdy polecenie zastępuje funkcje pierwszej klasy / lambdas. Z drugiej strony gość jest czymś zupełnie innym. Nie sądzę, że można to wyjaśnić w kilku zdaniach, więc proszę spojrzeć na en.wikipedia.org/wiki/Visitor_pattern
EricSchaefer
0

Oto podstawowy przykład:

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

Wynik:

Do println
Do print
BullyWiiPlaza
źródło
0

Nie znalazłem tutaj żadnego rozwiązania, które pokazuje, jak przekazać metodę z powiązanymi z nią parametrami jako parametrem metody. Poniżej przedstawiono przykład, w jaki sposób można przekazać metodę z już powiązanymi wartościami parametrów.

  1. Krok 1: Utwórz dwa interfejsy, jeden z typem zwrotu, drugi bez. Java ma podobne interfejsy, ale są mało praktyczne, ponieważ nie obsługują zgłaszania wyjątków.


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


    public interface Return {
        R run() throws Exception;
    }
  1. Przykład wykorzystania obu interfejsów do zawijania wywołania metody w transakcji. Zauważ, że przekazujemy metodę z rzeczywistymi parametrami.


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

Kolejny przykład pokazuje, jak przekazać metodę, która faktycznie coś zwraca



        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
źródło
0

Przykład rozwiązania z refleksją, przekazana metoda musi być jawna

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
źródło
0

Doceniam powyższe odpowiedzi, ale udało mi się osiągnąć to samo zachowanie, stosując poniższą metodę; pomysł zapożyczony z wywołań JavaScript. Jestem otwarty na korekty, ale jak dotąd tak dobrze (w produkcji).

Chodzi o to, aby w sygnaturze użyć typu zwracanego przez funkcję, co oznacza, że ​​wydajność musi być statyczna.

Poniżej znajduje się funkcja uruchamiająca proces z limitem czasu.

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
źródło