java - 带参数的可调用 lambda 表达式

标签 java lambda callable

我正在尝试使用泛型(我第一次尝试使用泛型)并使用 ExecutorService 来实现“TaskExecutor”。

这是我的“任务执行器”类:

public class ExecuteAlerterTask<T> {
    public List<T> process(String executorName, Callable<T> task) throws ExecutionException, InterruptedException {
        final ThreadFactory threadFactory = new ThreadFactoryBuilder()
                .setNameFormat(executorName + "-%d")
                .setDaemon(true)
                .build();
        ExecutorService executor = Executors.newFixedThreadPool(10, threadFactory);
        Collection<Future<T>> futures = new ArrayList<>();
        IntStream.range(1, 10).forEach(i -> {
            Future<T> future = executor.submit(task);
            futures.add(future);
        });

        List<T> result = new ArrayList<>();
        for (Future<T> f : futures) {
            result.add(f.get());
        }
        executor.shutdown();
        return result;
    }
}

这是我的运行方式:

@Test
public void process() throws Exception {
    Callable<String> callable = () -> "Do something on ";
    ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
    List<String> result = executeAlerterTask.process("TaskName", callable);
    result.forEach(System.out::println);
}

这是我的问题: 如何编写我的 Callable,它会在一行中接受参数 i:

Future<T> future = executor.submit(task);

例如期望的结果将是:

Do something on 1
Do something on 3
Do something on 7
Do something on 2
<...etc...>

如果我的代码有其他问题 - 请告诉我。

编辑

删除了可调用的实现

上面的代码是我真正想做的事情的抽象:

  • IntRange 实际上是我从 SQL 获取数据的一组批处理。可调用 真正实现了如何处理这些 SQL 批处理的逻辑。

EDIT2

在所有建议之后,我有以下解决方案:

public class ExecuteAlerterTask<T> {
    public List<T> process(String executorName, Collection<Callable<T>> task) throws ExecutionException, InterruptedException {
        final ThreadFactory threadFactory = new ThreadFactoryBuilder()
                .setNameFormat(executorName + "-%d")
                .setDaemon(true)
                .build();
        ExecutorService executor = Executors.newFixedThreadPool(10, threadFactory);
        Collection<Future<T>> futures = executor.invokeAll(task);

        List<T> result = new ArrayList<>();
        for (Future<T> f : futures) {
            result.add(f.get());
        }
        executor.shutdown();
        return result;
    }
}

运行方式:

   @Test
    public void process() throws Exception {
        Collection<Callable<String>> tasks = new ArrayList<>();
        IntStream.range(1, 10).forEach(i -> {
            tasks.add(new Task(i).callable);
        });

        ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
        List<String> result = executeAlerterTask.process("TaskName", tasks);
        result.forEach(System.out::println);
    }

    private class Task {
        private int i;
        private Callable<String> callable = () -> "Doing something on i: " + i;
        private Task(int i) {
            this.i = i;
        }
    }

EDIT3

更简单的运行方式:

   @Test
    public void process() throws Exception {
        Collection<Callable<String>> tasks = new ArrayList<>();
        IntStream.range(1, 10).forEach(i -> {
            tasks.add(() -> "Do something on i: " + i * 2);
        });

        ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
        List<String> result = executeAlerterTask.process("TaskName", tasks);
        result.forEach(System.out::println);
    }

我想我对最终解决方案非常满意。谢谢大家!

最佳答案

这是不可能的。如果是 lambda,则不能将变量传递给可调用对象。另一方面,您可以使用自己的特定对象来实现 Callable 并为变量设置一个 setter:

public class CallableWithParam implements Callable<String> {

    // protected for subclassing call()
    // volatile for multi-threaded reasons
    protected volatile int param = 0;

    public void setParam(int param) {
        this.param = param;
    }

    @Override
    public String call() {
        return "my param is: " + param;
    }

}

用法:

@Test
public void process() throws Exception {
    CallableWithParam callable = new CallableWithParam() {
    @Override
        public String call() {
             // an anonymous inner class is almost a lambda ;)
            return "my param is: " + param + "in subclass";
        }
    };
    callable.setParam(3);
    ExecuteAlerterTask<String> executeAlerterTask = new ExecuteAlerterTask<>();
    List<String> result = executeAlerterTask.process("TaskName", callable);
    result.forEach(System.out::println);
}

或者,您可以在构造函数中设置参数而不是 setter 。

关于java - 带参数的可调用 lambda 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46196676/

相关文章:

java - 如何使用具有多种消息类型的干扰器

java - Wicket:ListView - 跳过一个项目

python - 如何解决 Python 类型错误 : 'module' object is not callable?

java - jtable 自定义模型

Java 对象链表。我怎样才能统计每个独特的对象?

c++ - lambda 函数/表达式是否支持 constexpr?

lambda 表达式中的 C++ 模板仿函数

具有无限系列的 Java Stream-API 性能

swift - 是否可以调用 Any 的 callAsFunction() 变量?

java.util.concurrent.ExecutionException : java. lang.NullPointerException 错误