2012-06-18 23 views
45

¿Existe una interfaz en Java similar a la interfaz Callable, que puede aceptar un argumento para su método de llamada?¿Hay una interfaz similar a Callable pero con argumentos?

así:

public interface MyCallable<V> { 
    V call(String s) throws Exception; 
} 

yo preferiría evitar la creación de un nuevo tipo, si ya existe algo que pueda usar. ¿O hay una mejor estrategia para que varios clientes implementen y conecten una rutina invocable?

Copiado aquí http://www.programmingforums.org/thread27905.html

+1

No, pero ver cosas como http://www.programmingforums.org/thread27905.html. –

Respuesta

31

Desde Java 8 hay todo un conjunto de interfaces de función similar en the java.util.function package. El que está solicitando específicamente es simplemente Function.

Antes de Java 8, no había una interfaz integrada de propósito general para esto, pero algunas bibliotecas lo proporcionaban.

Por ejemplo Guava tiene the Function<F,T> interface con el método T apply(F input). También hace heavy use of that interface en varios lugares.

+0

Esta misma pregunta se le ocurrió a mis compañeros de trabajo la semana pasada.Nuestra primera y obvia elección fue utilizar la función de Guava. Sin embargo, notamos que el método apply() no arrojó excepciones. Esto lo hizo inadecuado para nuestros propósitos. Desafortunadamente, tuvimos que crear nuestra propia interfaz para eso. Al menos entró en una lib de toda la compañía, para ser reutilizado. –

+1

@FilipeFedalto: bueno, tanto 'throwing exceptioned and' throwing 'Function' puede ser útil. La mayoría de los usos de 'Function' en Guava son simples" convertir de a-a-b "y" obtener foo de un objeto Bar "que nunca deberían (en un programa sano) arrojar una excepción marcada (NPE y los no verificados son una historia diferente) Esa es (probablemente) por la cual la 'Función' de Guava no arroja excepciones. –

+0

¿Qué intentas _hacer_ con él? Una interfaz como esta solo es útil si su implementación le permite hacer las cosas mejor de lo que podría hacerlo con una implementación directa. Esto no siempre es cierto con 'Function', y mucho menos bestias más complicadas. –

1

La respuesta es ambigua. Estrictamente hablando, es decir, "con el mismo propósito de la interfaz invocable", no existe.

Existen clases similares, y dependiendo de lo que desee, pueden o no ser convenientes. Uno de ellos es el SwingWorker. Sin embargo, como su nombre lo indica, fue diseñado para su uso dentro del marco Swing. Podría ser utilizado para otros fines, pero esta sería una opción de diseño pobre.

Mi mejor consejo es usar uno proporcionado por una biblioteca de extensión (Jakarta-Commons, Guava, etc.), dependiendo de las bibliotecas que ya use en su sistema.

0

Normalmente no se requieren argumentos, ya que el método puede tener cualquier cantidad de argumentos en su constructor.

final int i = 5; 
final String word = "hello"; 

Future<String> future = service.submit(new Callable<String>() { 
    public String call() { 
     return word + i; 
    } 
}); 

En este ejemplo i y word se han utilizado, pero se puede "pasar" cualquier número de parámetros.

+0

En realidad, usted está en lo correcto, PERO solo para Extender, desde muchos puntos de vista, crear un nuevo objeto que se puede llamar cada vez puede ser sobrecargado e inútil. Ejemplo: luego procesa una gran colección por elemento individual, uno por uno, o cuando tiene algún Componente y debe entregarle el proceso (para evitar la lógica de mezcla/desorden). – iMysak

+0

@iMysak Para pasar trabajo entre subprocesos a través de una cola va a crear bastantes objetos (al menos 3 sospecho) –

+0

de hecho, desde este punto es totalmente correcto :) – iMysak

7

al principio pensé que esto se hace con una interfaz, pero luego descubrí que debería hacerse usando una clase abstracta.

lo he resuelto de esta manera:


edición: últimamente sólo tiene que utilizar esto:

public static abstract class callback1<T>{ 
     public abstract void run(T value); 
    } 

    public static abstract class callback2<T,J>{ 
     public abstract void run(T value,J value2); 
    } 

    public static abstract class callback3<T,J,Z>{ 
     public abstract void run(T value,J value2,Z value3); 
    } 


    public static abstract class callbackret1<R,T>{ 
     public abstract R run(T value); 
    } 

    public static abstract class callbackret2<R,T,J>{ 
     public abstract R run(T value,J value2); 
    } 

    public static abstract class callbackret3<R,T,J,Z>{ 
     public abstract R run(T value,J value2,Z value3); 
    } 

devolución de llamada.java

public abstract class CallBack<TRet,TArg> { 
    public abstract TRet call(TArg val); 
} 

definen método:

class Sample2 
{ 
    CallBack<Void,String> cb; 
    void callcb(CallBack<Void,String> CB) 
    { 
    cb=CB; //save the callback 
    cb.call("yes!"); // call the callback 
    } 
} 

uso del método:

sample2.callcb(new CallBack<Void,String>(){ 
     @Override 
     public Void call(String val) { 
      // TODO Auto-generated method stub 
      return null; 
     } 
    }); 

dos argumentos muestra: CallBack2.java

public abstract class CallBack2<TRet,TArg1,TArg2> { 
    public abstract TRet call(TArg1 val1,TArg2 val2); 
} 

nótese que cuando utiliza el tipo de devolución de nulo, debe utilizar return null; así que aquí hay una variación para corregirlo porque normalmente las devoluciones de llamada no devuelven ningún valor.

vacío como tipo de retorno: SimpleCallBack.java

public abstract class SimpleCallBack<TArg> { 
    public abstract void call(TArg val); 
} 

void como tipo de retorno 2 args: SimpleCallBack2.java

public abstract class SimpleCallBack<TArg1,TArg2> { 
    public abstract void call(TArg1 val1,TArg2 val2); 
} 

interfaz no es útil para esto.

Las interfaces

permiten que varios tipos coincidan con el mismo tipo. teniendo un conjunto de funciones predefinido compartido.

Las clases abstractas permiten que las funciones vacías dentro de ellas se completen más tarde. en la extensión o instanciación.

+0

También creo que su clase abstracta 'CallBack' debería ser una interfaz, solo para permitir la herencia múltiple (ejemplo rápido: hacer que una clase hija extienda una de sus clases, y ser un 'CallBack' al mismo tiempo). ¿Qué te hizo cambiar tu opinión? –

+0

tengo la sensación de que puedes lanzar antes de pasarlo como argumento. también la clase abstracta puede implementar una interfaz que puede poner como argumento y no requiere conversión –

+0

Todavía no veo la ventaja de usar una clase abstracta: estas son más útiles cuando se usan para proporcionar métodos que deben implementarse en subclases junto con un esqueleto implementación que facilita el desarrollo de las subclases. Aquí no tiene ningún código en sus clases abstractas, solo métodos abstractos. Por lo tanto, podrías usar interfaces en su lugar. –

4

He tenido el mismo requisito recientemente. Como otros han explicado, muchas bibliotecas proporcionan métodos "funcionales", pero no arrojan excepciones.

Un ejemplo de cómo algunos proyectos han proporcionado una solución es la bibliotecaRxJava donde utilizan interfaces como accionX donde 'x' es 0 ... n, el número de argumentos para la llamada método . Incluso tienen una interfaz varargs, ActionN.

Mi enfoque actual es utilizar una sencilla interfaz genérica:

public interface Invoke<T,V> {  
    public T call(V data) throws Exception;  
// public T call(V... data) throws Exception;  
} 

El segundo método es preferible en mi caso, pero exhibe la temida "seguridad Tipo: contaminación montón de potencial a través de varargs datos de parámetros" en mi IDE , y ese es un problema completamente diferente.

Otro enfoque que estoy mirando es el uso de las interfaces existentes, tales como java.util.concurrent.Callable que no lanzan una excepción, y en mi implementación excepciones envoltura de excepciones sin marcar.

0

Acabo de tener el mismo problema. puede ajustar cualquier método para devolver un invocable y ejecutar su valor devuelto. decir

main {  
    Callable<Integer> integerCallable = getIntegerCallable(400); 
    Future<Integer> future = executor.submit(integerCallable); 
} 

private Callable<Integer> getIntegerCallable(int n) { 
    return() -> { 
      try { 
       TimeUnit.SECONDS.sleep(n); 
       return 123; 
      } catch (InterruptedException e) { 
       throw new IllegalStateException("task interrupted", e); 
      } 
     }; 
} 
Cuestiones relacionadas