【问题标题】:Declare array of lambdas in Java在 Java 中声明 lambda 数组
【发布时间】:2017-12-06 16:51:41
【问题描述】:

我想创建一个 lambda 数组。问题是 lambda 可能彼此不同。示例:

private interface I0 {
    int interface0(int a, int b);
}

private interface I1 {
    int interface1(double d);
}

现在,如何声明一个可以同时包含 I0 和 I1 的列表?

List<Object> test = Arrays.asList(
        (int a, int b) -> a + b,
        (double d) -> d * 2
);

显然Object 不起作用。

【问题讨论】:

  • 您能解释一下您的用例吗?我认为这有难闻的气味。
  • 每个接口都应该“映射”函数的参数。我想根据一些标准生成每个参数。
  • 如果您将方法定义更改为相同是否可以?例如double interface1(double d, double amount /* instead of 2 - pass some amount*/);?
  • @TimB 可能是因为 lambda 映射没有唯一的接口。至少,代码缺少显式转换。
  • @Surcle 问题是:你打算用这个列表做什么?您如何确定您是尝试使用一个参数还是使用两个参数进行调用?

标签: java lambda


【解决方案1】:

您必须首先将 lambda 表达式分配给函数式接口类型的变量。

否则编译器无法推断这些 lambda 表达式的类型。

I0 i0 = (int a, int b) -> a + b;
I1 i1 = (double d) -> (int) (d * 2);
List<Object> test = Arrays.asList(
    i0,
    i1
);

也就是说,我不确定将这些 lambda 表达式存储在 List&lt;Object&gt; 中的意义何在。如果不将它们转换回单独的功能接口类型,就无法使用它们。

【讨论】:

  • 只是一点点(侧面?)注意:可能更好地使用(int) (d * 2),即转换乘法的结果,而不仅仅是d
  • @CarlosHeuberger 好点。我只添加了强制转换,以便 lambda 表达式匹配 I1 接口,并不关心细节(假设这可能只是一个示例,而不是 OP 将使用的实际 lambda 表达式)。
【解决方案2】:

您可以转换为相应的接口,例如:

List<Object> test = Arrays.asList(
    (I0) (int a, int b) -> a + b,
    (I1) (double d) -> (int) (d * 2)
);

尽管它更短,但我也会考虑 Eran's answer 或许它更具可读性和更易于理解(如果有更多功能)。而且我也看不到这种构造的用例......

它变得更短(不一定更好):

List<Object> test = Arrays.asList(
    (I0) (a, b) -> a + b,
    (I1) d -> (int) (d * 2)
);

【讨论】:

    【解决方案3】:

    据我所知,您正在尝试做这样的事情:

    public static void main(String... args){
        List<Object> lambdas = Arrays.asList(
                (IntBinaryOperator) (int a, int b) -> a + b,
                (DoubleToIntFunction) (double d) -> (int)(d * 2)
        );
        for(int i=0;i<args.length;i++){
            // Apply lambdas.get(i) to args[i]
        }
    }
    

    不过,这条评论很重要;你将如何实现它?

    您可以在每一轮中检查类型:

        for(int i=0;i<args.length;i++){
            if(lambdas.get(i) instanceof IntBinaryOperator){
                processedArgs[i] =
                        ((IntBinaryOperator) lambdas.get(i)).applyAsInt(MAGIC_NUMBER, Integer.parseInt(args[i]));
            }else{
                // All your other cases (may take a while)
            }
        }
    

    验证每一种可能的类型是一件非常痛苦的事情,如果它依赖于位置,那么它无论如何只会运行一次,所以它是矫枉过正的。

    我的建议取决于这是静态的(您的代码只在一组特定的参数上运行)还是动态的(它需要在各种参数上运行)。对于静态代码,我只应用没有循环的 lambda:

    public static void main(String... args){
        processedArgs = new int[args.length];
        IntBinaryOperator op1 = (int a, int b) -> a + b;
        DoubleToIntFunction op2 =  (double d) -> (int)(d * 2);
    
        processedArgs[0] = op1.applyAsInt(MAGIC_NUMBER, Integer.parseInt(args[0]));
        processedArgs[1] = op2.applyAsInt(Double.parseDouble(args[1]));
    }
    

    对于动态解决方案,我建议切换到单一功能界面。我会采用最大要求并在不需要的地方填写虚拟值:

    public static void main(String... args){
        processedArgs = new int[args.length];
        List<DoubleBinaryOperator> ops = Arrays.asList(
                (a, b) -> a + b,
                (d, ignore) -> (d * 2)
        );
        for(int i=0;i<args.length;i++){
            processedArgs[i] = (int)ops.get(i).applyAsDouble(Double.parseDouble(args[i]), MAGIC_NUMBER);
        }
    }
    

    或者,如果您可以简化您的 lambda,最好:

    public static void main(String... args){
        processedArgs = new int[args.length];
        List<DoubleToIntFunction> ops = Arrays.asList(
                (d) -> (int)(d + MAGIC_NUMBER),
                (d) -> (int)(d * 2)
        );
        for(int i=0;i<args.length;i++){
            processedArgs[i] = ops.get(i).applyAsInt(Double.parseDouble(args[i]));
        }
    }
    

    我觉得您的解决方案最终比其中任何一个都简单。只是想帮助您指出正确的方向。

    【讨论】:

      【解决方案4】:

      你可以让你的界面使用可变参数类型:

      public class NaryFunctionTest {
      
          interface NaryFunction<R extends Number> {
              R run(R... args);
          }
      
          @Test
          public void test() {
              NaryFunction<Integer> f1 = (Integer[] o) -> o[0] + o[1];
              NaryFunction<Double> f2 = (Double[] o) -> o[0] *2;
              List<NaryFunction<?>> test = Arrays.asList(
                  f1,
                  f2
              );
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-20
        • 2020-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多