Declare array of lambdas in Java

匆匆过客 提交于 2020-08-24 05:41:11

问题


I'd like to create an array of lambda. The problem is that the lambda could be different from each other. Example:

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

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

Now, how can I declare a list which can contain both I0 and I1?

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

Obviously Object does not work.


回答1:


You must assign the lambda expressions to variables of the functional interface types first.

Otherwise the compiler cannot infer the types of these lambda expressions.

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

That said, I'm not sure what's the point of storing these lambda expressions in a List<Object>. You can't use them without casting them back to the individual functional interface types.




回答2:


You could cast to the respective Interface like:

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

despite this being shorter, I would also consider Eran's answer maybe it is more readable and easier to understand (if having more functions). And I also can't see the use case for such a construct...

It gets even shorter (not necessarily better):

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



回答3:


From what I gather, you're trying to do something like this:

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]
    }
}

That comment is a pretty big deal, though; how would you implement it?

You could check the type during each round:

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

Validating each possible type is a huge pain, and if it's position-dependent, it's only going to run once anyway, so it's overkill.

My recommendation depends on if this is going to be static (your code runs only on one specific set of arguments ever) or dynamic (it needs to run on all kinds of arguments). For static code, I'd just apply the lambdas without a loop:

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

For a dynamic solution, I'd recommend switching to a single functional interface. I would go with the maximum requirement and fill in dummy values where not needed:

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

Or, preferably, if you can simplify your lambdas:

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

I feel like your solution ultimately is less complicated than any of these. Just trying to help point you in the right direction.




回答4:


You could make your interfaces use vararg typing:

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


来源:https://stackoverflow.com/questions/47650162/declare-array-of-lambdas-in-java

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!