2012-06-18 3 views
45

Есть ли интерфейс на Java, похожий на интерфейс Callable, который может принимать аргумент в свой метод вызова?Есть ли интерфейс, похожий на Callable, но с аргументами?

Как так:

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

я предпочел бы избежать создания нового типа, если уже существует что-то, что я могу использовать. Или есть лучшая стратегия для внедрения нескольких клиентов и включения подпрограммы?

Скопировано здесь http://www.programmingforums.org/thread27905.html

+1

Нет, но видеть вещи, как http://www.programmingforums.org/thread27905.html. –

ответ

31

Поскольку Java 8 имеется целый набор функций, как интерфейсы в the java.util.function package. Тот, который вы просите специально, это просто Function.

До Java 8 для этого не было встроенного интерфейса общего назначения, но некоторые библиотеки предоставили его.

Например, Guava имеет the Function<F,T> interface способом T apply(F input). Он также составляет heavy use of that interface в нескольких местах.

+0

Этот же вопрос возник у моих сотрудников на прошлой неделе.Наш первый и очевидный выбор заключался в использовании функции от Guava. Однако мы заметили, что метод apply() не генерировал исключений. Это сделало его непригодным для наших целей. К сожалению, для этого нам пришлось создать собственный интерфейс. По крайней мере, он попал в общесистемную библиотеку, чтобы ее снова использовали. –

+1

@FilipeFedalto: ну, как исключение, так и бросание «Функция» могут быть полезны. Большинство использования 'Function' в Guava - это простые« конвертировать a-to-b »и использовать« get foo from Bar object », которые никогда не должны (в разумной программе) вызывать проверенное исключение (NPE и непроверенные - это другая история). Это (вероятно), почему Guava 'Function' не генерирует исключений. –

+0

Что вы пытаетесь _do_ с этим? Такой интерфейс полезен только тогда, когда его реализация позволяет вам делать что-то лучше, чем вы могли с прямой реализацией. Это не всегда верно для 'Function', не говоря уже о более сложных зверях. –

1

Ответ неоднозначен. Строго говоря, то есть «с той же целью интерфейса Callable», нет.

Существуют аналогичные классы, и в зависимости от того, что вы хотите, они могут быть или не быть удобными. Один из них - SwingWorker. Однако, как следует из названия, он был разработан для использования в рамках Swing. Его можно использовать для других целей, но это будет плохой выбор дизайна.

Мой лучший совет - использовать предоставленную библиотекой расширений (Jakarta-Commons, Guava и т. Д.) В зависимости от того, какие библиотеки вы уже используете в своей системе.

0

Обычно аргументы не требуются, поскольку метод может иметь любое количество аргументов в своем конструкторе.

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

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

В этом примере i и word были использованы, но вы можете «передать» любое количество параметров.

+0

На самом деле вы правы, НО просто для расширения, со многих точек зрения создание нового объекта Callable каждый раз может быть накладным и бесполезным. Пример. Затем вы обрабатываете большую коллекцию одним элементом, один за другим, или когда у вас есть какой-то компонент, и вы должны передать ему процесс доставки (чтобы избежать логики смешивания/беспорядка). – iMysak

+0

@iMysak Чтобы передать работу между потоками через очередь, вы собираетесь создать довольно много объектов (по крайней мере, я подозреваю 3) –

+0

действительно, с этого момента вы полностью правы :) – iMysak

7

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

я решил так:


изменения: в последнее время я просто использовать это:

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

CallBack.Java

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

определяют метод:

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

метод использования:

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

два аргумента образца: CallBack2.java

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

Обратите внимание, что при использовании типа возврата Void вам необходимо использовать return null; , так что здесь есть вариант исправить это, потому что обычно обратные вызовы не возвращают никакого значения.

недействительными в качестве возвращаемого типа: SimpleCallBack.java

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

недействительными, как возвращение типа 2 арг: SimpleCallBack2.java

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

интерфейс не является полезным для этого.

интерфейсы позволяют использовать несколько типов одинакового типа. имея общий предопределенный набор функций.

абстрактные классы позволяют пустым функциям внутри них заполняться позже. при расширении или создании экземпляра.

+0

Я также считаю, что ваш абстрактный класс 'CallBack' должен быть интерфейсом, если только разрешить множественное наследование (быстрый пример: иметь дочерний класс, расширяющий один из ваших классов, и одновременно быть «CallBack»). Почему вы изменили свое мнение? –

+0

У меня есть чувство, которое вы можете использовать, прежде чем передать его в качестве аргумента. также абстрактный класс может реализовать интерфейс, который вы можете поставить как аргумент, и не требует литья –

+0

Я до сих пор не вижу преимущества использования абстрактного класса: они наиболее полезны при использовании для предоставления методов, которые должны быть реализованы в подклассах вместе с скелетным что облегчает разработку подклассов. Здесь у вас нет кода в ваших абстрактных классах, просто абстрактных методах. Следовательно, вы могли бы просто использовать интерфейсы. –

4

В последнее время у меня было такое же требование. Как объяснили другие, многие библиотеки предоставляют «функциональные» методы, но они не генерируют исключений.

Пример того, как некоторые проекты обеспечили решение является библиотекой RxJava, где они используют интерфейсы, такие как ActionX где «X» является 0 ... N, количество аргументов в вызов методы , У них даже есть интерфейс varargs, ActionN.

Мой текущий подход заключается в использовании простой общий интерфейс:

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

Второй способ предпочтительнее в моем случае, но он показывает, что Страшный «Тип безопасности: Потенциал загрязнения кучи с помощью переменной длины данных параметра» в моем IDE , и это совсем другая проблема.

Другого подход, который я смотрю на это, чтобы использовать существующие интерфейсы, такие как java.util.concurrent.Callable, которые не бросают исключения, и в моих исключениях обертывания реализации в непроверенных исключениях.

0

У меня была такая же проблема. вы можете обернуть любой метод, чтобы вернуть вызываемый, и выполнить его возвращаемое значение. т.е.

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