当前位置: 首页 > 知识库问答 >
问题:

找到包装可运行方法的优雅方法,并在java中将其作为函数传递

孙昂然
2023-03-14

使用java 11的Im,假设我有多个可运行的方法,它们都是相同的结构,只是参数的数量不同,如示例所示:

private Runnable deleteIndex(String targetIndex) {
        return () -> {
            try {
                iIndexerManagementService.deleteIndex(targetIndex);
            } catch (Exception e) {
                log.error("Cannot perform delete:", e);
            }
        };
    }
    
    
private Runnable deleteDataBySource(String targetIndex, String source) {
        return () -> {
            try {
                indexerDocumentService.deleteBySource(targetIndex, source);
            } catch (Exception e) {
                log.error("Cannot perform delete:", e);
            }
        };
    }
    
    
private Runnable createDeleteTaskByScanID(String targetIndex, String scandId, String source) {
        return () -> {
            try {
                indexerDocumentService.deleteByScanId(targetIndex, scandId, source);
            } catch (Exception e) {
                log.error("Cannot perform delete:", e);
            }
        };
} .... 
  and more ....

稍后,我将在每个可运行方法上使用它,如下所示:

    public void submitDeleteIndexTask(String targetIndex) {
       Optional.ofNullable(syncControlRepository.findByName(CATALOG_ENTITY_TYPE_KEYWORD))
                        .ifPresent(strategy -> {
                            Future<?> future =  uploadersExecutor.submit(deleteIndex(targetIndex));
                            if (featureFlagEnabled && config.isTestProfile()) {
                                try {
                                    future.get(1, TimeUnit.MINUTES);
                                } catch (Exception e) {
                                    log.error("Cannot wait on thread block:", e);
                                }
                            }
                    });
            } 
.... and more

我做得很好。

但我想找到一种更好的优雅方式,不在类中容纳大量可运行的方法,因为它可能会更多。我的目的是创建一个通用的可运行包装器,以便能够传递任何类型的函数,因此在使用它时,我只传递函数本身和要调用的参数。

我这样想过,有点我不确定这是正确的

// generic runnable wrapper to pass any function

    public Runnable runAsync(Function foo, Object o) {
        return () -> {
            try {
                foo.apply(o);
            } catch (Exception e) {
                log.error("Cannot perform delete:", e);
            }
        };
    }

然后它应该是1个通用方法,能够接收函数以适应runnables方法:

public void runGeneralAsync(... HERE PASS FUNCTION ..??. ) {
        Optional.ofNullable(syncControlRepository.findByName(CATALOG_ENTITY_TYPE_KEYWORD))
                .ifPresent(strategy -> {
                    Future<?> future =  uploadersExecutor.submit(runAsync(....FUNCTOIN... ?? ));
                    if (featureFlagEnabled && config.isTestProfile()) {
                        try {
                            future.get(1, TimeUnit.MINUTES);
                        } catch (Exception e) {
                            log.error("Cannot wait on thread block:", e);
                        }
                    }
            });
    }

请给出建议

共有1个答案

林德惠
2023-03-14

您所要求的等同于“stringly-typed”/动态,并且从根本上讲是不符合实际的。你可能认为你想要这个;如果你尝试的话,整个java生态系统将在每一步都与你斗争。

注意:你的runGeneralAsync糟糕透顶,你在这里滥用了Optional。这段代码是一种冗长的说法:查找一个东西,如果它确实存在,就这样做,如果它不存在,就默默地什么也不做。除了长篇大论之外(如果没有什么不对的),“什么都不做”是一种可怕的倒退。从某种意义上讲,很可怕:名称或设置中的一个bug意味着什么都不会发生,因此,您将在几个小时内追踪该bug。NPE需要1分钟。如果你写的代码无法理解空值,就直接写吧。如果发生null,则需要该异常,以便知道在何处进行修复。

无论如何:

相反,Runnable本身就是答案。将lambdas包裹在lambdas中。

你在想这样的事情:


// API:
public void runGeneralAsync(String methodName, Object... args) {
  // Lots of reflective shenanigans to find it.
  // Lots of issues with dealing with exceptions -
  // what if the method name does not exist? What if the wrong amount
  // of args were passed? Or the wrong type? Or there is an overload?

  // .. and then of course code to stick it all into an executor.submit
}

// usage:

runGeneralAsync("deleteIndexTask", "my-index");

但是你想做的是这样的:

public void runGeneralAsync(Runnable task) {
  uploadersExecutor.submit(runAsync(....));
}

// usage:

runGeneralAsync(() -> deleteIndex("my-index"));

根据需要,您可能希望在此处使用可调用的,而不是可运行的(您可以返回东西,也可以抛出东西)。

 类似资料:
  • 问题内容: 我试图将选择的A类“获取”方法传递给B类中的方法。我已经将Java PassMethod作为Parameter签出,但是我无法以合理的方式采用接口方法解决问题。我宁愿 不 使用Java 8(lambdas),并尽可能避免反射。我的感觉是,我以错误的方式看待自己的问题。这是我要完成的工作的特定简化示例: 我有一个包含一些字段和get-method的类: 接下来,我将主类实例化为Map的V

  • 问题内容: 我试图制作一个程序,当类名和方法名作为String参数传递给调用者时,该程序执行特定的方法。考虑下面的代码。我有一个CarBean类: 现在,我想通过以下方法运行此文件: runTheMethod的实现如下所示: 我可以使用类名来获取对象。现在,我需要将其强制转换为CarBean对象,然后可以运行其方法。因此,想知道如何在运行时将其强制转换为类名对于每个调用都会有所不同。另外,在尝试调

  • 问题内容: 我试图衡量几种方法的执行时间。所以我在想做一个方法,而不是多次重复相同的代码。 这是我的代码: 假设我有,如何使用它来衡量执行时间? 问题答案: 方法不是Java中的一流对象,因此不能将它们作为参数传递。您可以将方法调用包装在扩展例如接口的匿名类中:

  • 当我构建这个应用程序时,我得到错误: 我也试过: 这将错误更改为: 下面是调用这个例程的类和我传递的回调函数的示例:

  • 我编写了一个方法,它接收一个可调用的字符串和一个任意长度的字符串数组,我使用这些字符串来确定可调用的执行时间,然后将结果写入数据库: 这很好,但是我现在遇到了一种情况,我需要将Callable的返回值作为参数传递给相同的方法: 此方法一直等待,直到加载页并返回加载页的名称。我希望在调用中使用该返回值作为参数,而是其参数之一。 现在,按预期返回页名,但将写入数据库,以获得的结果。 有没有办法做到这一

  • 我正在编写一个方法,如果我想将一个类传递给一个方法,其中代码的一部分包括检查对象是否属于某种类型。这就是我想要的(但显然不行): 关于如何做到这一点有什么提示吗?谢谢!