【问题标题】:Is there an interface similar to Callable but with arguments?是否有类似于 Callable 但带有参数的接口?
【发布时间】:2012-06-20 11:35:35
【问题描述】:

Java 中是否有类似于Callable 接口的接口,可以接受其调用方法的参数?

像这样:

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

如果已经存在我可以使用的东西,我宁愿避免创建新类型。或者有没有更好的策略让多个客户端实现并插入一个可调用的例程?

从这里复制http://www.programmingforums.org/thread27905.html

【问题讨论】:

标签: java interface


【解决方案1】:

从 Java 8 开始,the java.util.function package 中有一整套类似函数的接口。您具体要求的只是Function。

在 Java 8 之前,没有通用的内置接口,但一些库提供了它。

例如Guava 具有the Function&lt;F,T&gt; interface 和T apply(F input) 方法。它还在几个地方制作了heavy use of that interface。

【讨论】:

  • 上周我的同事也遇到了同样的问题。我们的第一个也是显而易见的选择是使用来自 Guava 的 Function。但是我们注意到 apply() 方法没有抛出异常。这使得它不适合我们的目的。不幸的是,我们最终不得不为此创建自己的界面。至少它进入了公司范围的库,可以重复使用。
  • @FilipeFedalto:好吧,抛出异常和不抛出 Function 都可能有用。 Guava 中Function 的大多数用法都是简单的“将 a-to-b 转换为 b”和“从 Bar 对象获取 foo”的用法,它们永远不应该(在理智的程序中)抛出已检查的异常(NPE 和未检查的异常是另一回事)。这(可能)是 Guava Function 不抛出异常的原因。
  • 你想用它做什么?像这样的接口只有在实现它可以让您比直接实现做得更好时才有用。 Function 并非总是如此,更不用说更复杂的野兽了。
【解决方案2】:

答案是模棱两可的。严格来说,就是“同Callable接口一样”,是没有的。

有类似的课程,根据您的需要,它们可能方便也可能不方便。其中之一是SwingWorker。但是,顾名思义,它是为在 Swing 框架中使用而设计的。它可以用于其他目的,但这将是一个糟糕的设计选择。

我的最佳建议是使用扩展库(Jakarta-Commons、Guava 等)提供的扩展库,具体取决于您系统中已使用的库。

【讨论】:

    【解决方案3】:

    通常不需要参数,因为方法在其构造函数中可以有任意数量的参数。

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

    在本例中,i 和 word 已被使用,但您可以“传递”任意数量的参数。

    【讨论】:

    • 实际上你是对的,但只是为了扩展,从很多角度来看,每次创建新的 Callable 对象可能是开销和无用的。示例 - 然后您按单个元素,一个一个地处理大集合,或者当您有一些组件并且您应该将流程交付给他(以避免混合/混乱逻辑)。
    • @iMysak 要通过队列在线程之间传递工作,您将创建相当多的对象(我怀疑至少 3 个)
    【解决方案4】:

    起初它认为这是通过接口完成的,但后来我发现它应该使用抽象类来完成。

    我是这样解决的:


    编辑:最近我只用这个:

        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; 所以这里有一个变体来解决这个问题,因为通常回调不返回任何值。

    void 作为返回类型:SimpleCallBack.java

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

    void 作为返回类型 2 参数:SimpleCallBack2.java

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

    接口对此没有用。

    接口允许多个类型匹配同一个类型。通过共享一组预定义的函数。

    抽象类允许稍后完成其中的空函数。在扩展或实例化。

    【讨论】:

    • 我也认为你的 CallBack 抽象类应该是一个接口,如果只是为了允许多重继承(快速示例:让一个子类扩展你的一个类,并成为 CallBack 在同时)。是什么让你改变了看法?
    • 我有一种感觉,您可以在将其作为参数传递之前进行转换。抽象类也可以实现一个可以作为参数而不需要强制转换的接口
    • 我仍然看不到使用抽象类的优势:当用于提供必须在子类中实现的方法以及简化子类开发的骨架实现时,这些是最有用的。在这里,您的抽象类中没有任何代码,只有抽象方法。因此,您可以只使用接口。
    • 抽象类就像一个谜题,缺少一块你可以用自己的代码完成。在强类型语言中,接口是匹配任何多种类型的实用程序。但是,您必须首先声明一个类。因此,您需要一些抽象类来在其中放置一个方法。
    【解决方案5】:

    我最近也有同样的要求。正如其他人所解释的那样,许多库确实提供了“功能”方法,但这些方法不会引发异常。

    一些项目如何提供解决方案的一个例子是 RxJava 库,它们使用诸如 ActionX 之类的接口,其中 'X' 是 0 ... N, call 方法的参数数量。他们甚至有一个可变参数接口,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,并在我的实现中将异常包装在未经检查的异常中。

    【讨论】:

      【解决方案6】:

      我也遇到了同样的问题。您可以包装任何方法以返回可调用对象,并执行它的返回值。 即

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

      【讨论】:

        【解决方案7】:

        从 Java 1.8 开始有一个Supplier&lt;T&gt; 接口。它有一个get() 方法而不是call(),并且它没有声明任何抛出的异常。

        【讨论】:

          【解决方案8】:

          像这样定义一个接口:

          interface MyFunction<I, O> {
              O call(I input);
          }
          

          定义一个方法:

          void getOrderData(final Function<JSONArray, Void> func){
              ...
              JSONArray json = getJSONArray();
              if(func!=null) func.call(json);           
          }
          

          使用示例:

          //call getOrderData somewhere in your code
          getOrderData(new Function<JSONArray, Void>() {
                  @Override
                  public Void call(JSONArray input) {
                      parseJSON(input);                
                      return null;
                  }
          });
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-08-19
            • 2016-01-13
            • 2014-07-02
            • 1970-01-01
            • 2020-12-02
            • 2014-08-14
            • 2021-04-25
            • 1970-01-01
            相关资源
            最近更新 更多