是否存在通过方法引用使方法调用函数成为动态数量的参数的解决方案?

时间:2017-04-08 09:42:28

标签: java generics lambda java-8

所以,我有以下课程:

public class MainClass{

    public void run(String infoOne, String infoTwo, String infoThree, String infoFour, String infoFive, String infoSix){        
        SomeClass someClass = new SomeClass();
        someClass.runSomeMethod();
        someClass.runSomeMethodTwo( infoOne);
        someClass.runSomeMethodThree( infoThree, infoOne, infoSix);
        someClass.runSomeMethodFour( infoTwo, infoFive);
        someClass.runSomeMethodFive(infoThree, infoFive, infoOne, infoSix);
    }
}

public class SomeClass{
    public boolean runSomeMethod(){
        // do something
    }

    public boolean runSomeMethodTwo(String arg){
        // do something
    }

    public boolean runSomeMethodThree(String argOne, String argTwo, String argThree){
        // do something
    }

    public boolean runSomeMethodFour(String argOne, String argTwo){
        // do something
    }

    public boolean runSomeMethodFive(String argOne, String argTwo, String argThree, String argFour){
        // do something
    }
}

正如你所看到的那样,一系列方法只将Strings作为参数(但每次都有不同的数量)。我现在想要的是将每个方法包装在try catch块中并记录一些结果。为此,我想在其间设置一个处理日志记录的方法:

log(SomeClass::runSomeMethodFour);

public void log(????? method, String...args){
    try{
        if(method.execute(args);
            System.out.println("Success!");
        } else {
            System.out.println("Failed to execute!");
        }
    } catch (Exception e){
        e.printStackTrace();
    }
}

这有可能吗?要将动态数量的参数传递给lambda函数?或者我可以用泛型做点什么吗?

3 个答案:

答案 0 :(得分:2)

JLS描述了方法参考表达式:

  

方法引用的编译时声明是表达式引用的方法。在特殊情况下,编译时声明实际上并不存在,但它是一个表示类实例创建或数组创建的名义方法。编译时声明的选择取决于表达式所针对的函数类型,就像方法调用的编译时声明依赖于调用的参数一样。

     

如果T是函数接口类型(第9.8节)且表达式与地面目标类型的函数类型一致,则方法引用表达式在赋值上下文,调用上下文或具有目标类型T的转换上下文中是兼容的源自T。

方法引用表达式必须在编译时准确分配Function Interface。和功能接口是 SAM 接口。所以你不能在运行时通过方法引用表达式动态绑定方法处理程序。

但您可以使用reflectioninvoke api来实现它。

让我们看看每个方法表达式引用SomeClass中的函数接口结果是指不同的函数接口类型:

SomeClass it = new SomeClass();

BooleanSupplier first1 = it::runSomeMethod;//bound
Predicate<SomeClass> first2 = SomeClass::runSomeMethod;//unbound

Predicate<String> second1 = it::runSomeMethodTwo;//bound
BiPredicate<SomeClass, String> second2 = SomeClass::runSomeMethodTwo;//unbound

...

答案 1 :(得分:2)

无需创建复杂的基于反射的解决方案。您的问题源于不必要的尝试分离方法和参数参数,而不是仅仅封装整个操作,如

public class MainClass {
    public void run(String infoOne, String infoTwo, String infoThree,
                    String infoFour, String infoFive, String infoSix) {        
        SomeClass someClass = new SomeClass();
        log(() -> someClass.runSomeMethod());
        log(() -> someClass.runSomeMethodTwo(infoOne));
        log(() -> someClass.runSomeMethodThree(infoThree, infoOne, infoSix));
        log(() -> someClass.runSomeMethodFour(infoTwo, infoFive));
        log(() -> someClass.runSomeMethodFive(infoThree, infoFive, infoOne, infoSix));
    }
    public void log(BooleanSupplier method) {
        try {
            if(method.getAsBoolean()) {
                System.out.println("Success!");
            } else {
                System.out.println("Failed to execute!");
            }
        } catch (Exception e ){
            e.printStackTrace();
        }
    }
}

对于log方法的工作,只有boolean返回值是相关的,它与BooleanSupplier的功能签名相匹配。

答案 2 :(得分:1)

听说&#34;反思&#34;作为Oliver Charlesworth的评论,我提出了以下解决方案:

public class Test {
    static Test testLogger = new Test(); //This should be another class ofcourse, but it doesn't matter for this example

    public static void main(String[] args) throws NoSuchMethodException, SecurityException{
        Test test = new Test();

        run(test, "something", "hi", "hai", "blaa");
    }

    public static void run(Object pageObjectModel, String methodName, String...arguments){
        Class<String>[] args = new Class[arguments.length];
        Arrays.fill(args, String.class);
        try {
            testLogger.log(pageObjectModel, pageObjectModel.getClass().getMethod(methodName, args), arguments);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
    }

    private void log(Object pageObjectModel, Method method, String...arguments) {
        try {
            if((Boolean)method.invoke(pageObjectModel, (Object[])arguments)){
                System.out.println("Success!");
            } else {
                System.out.println("Fail!");
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public boolean something(String one, String two, String three){
        System.out.println(one+", "+two+", "+three);
        return true;
    }
}

这对我想要实现的目标来说似乎是完美的。虽然我不喜欢反思,因为它有不好的经验(给出混淆代码的问题),我觉得这个项目很好。

感谢您帮助我朝着正确的方向前进!