如何在流lambda函数中实例化一个列表?

时间:2018-02-19 11:10:47

标签: java concurrency

我想创建一个列表的CompletableFuture。对于任何失败的元素,我想在单独的列表中收集失败的元素(用于进一步处理)。

问题:'错误集合'必须为final才能在lambda表达式中添加元素。 但大多数时候,我没有任何例外,因此列表的实例化是没用的。

//just an example list to illustrate
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

List<Integer> errors = null; //non final

List<CompletableFuture<Integer>> futures =
            list.stream()
                    .map(i -> CompletableFuture.supplyAsync(
                            () -> {
                                if (i % 2 == 0) throw new RuntimeException(i); //dummy business logic exception
                                return i;
                            })
                            .exceptionally(ex -> {
                                if (errors == null) errors = new ArrayList<>(); //TODO: invalid as written
                                errors.add(i);//TODO: invalid as written
                                return null;
                            })
                    )
                    .collect(Collectors.toList());

问题:这有可能吗?

4 个答案:

答案 0 :(得分:1)

解决方案解决方案:您是否也可以将初始List<Integer>用作 errorsList

List中删除所有符合您业务条件的元素。

List<CompletableFuture<Integer>> futures = list.stream()
    .map(i -> CompletableFuture.supplyAsync( () -> {

          synchronized (list) {
              // not a dummy business error
              if (i % 2 != 0) {
                  list.remove(i);
              }
          }
          return i;
     })).collect(Collectors.toList());

最后,list将仅包含错误。并且你不会再有一个空的未使用的Collection,这会让你烦恼。

请注意,它不会与Arrays.asList(T...);一起使用,因为它会返回一个java.util.Arrays.ArrayList实例,该实例是不可修改的。

我个人不喜欢这个解决方案:

  • 使用synchronized阻止
  • 在{lambda
  • 中使用synchronized阻止
  • 在不使用List
  • 的情况下迭代时删除Iterator中的元素
  • 将相同的对象用于两个不同的目的

答案 1 :(得分:0)

我能让它工作的唯一方法是使错误列表成为一个私有的静态ArrayList,它将Objects作为元素。走这条路意味着很多被压制的警告。通过这样做,我能够在错误列表中获得2和4。我希望这有帮助!

public class Main {

private static ArrayList<Object> errors;

public static void main(String[] args) {

    //just an example list to illustrate
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

    List<CompletableFuture<Integer>> futures =
                list.stream()
                        .map(i -> CompletableFuture.supplyAsync(
                                () -> {
                                    if (i % 2 == 0) throw new RuntimeException(i.toString()); //dummy business logic exception
                                    return i;
                                })
                                .exceptionally(ex -> {
                                    if (errors == null) errors = new ArrayList<>(); 
                                    errors.add(i);
                                    return null;
                                })
                        )
                        .collect(Collectors.toList());

    System.out.println(errors);
}

}

答案 2 :(得分:0)

我找到了使用BiConsumer的方法:

BiConsumer<Throwable, Integer> handler = new BiConsumer<Throwable, Integer>() {
    List<Integer> errors;

    @Override
    public void accept(Throwable throwable, Integer i) {
        if (errors == null) errors = new ArrayList<>();
        errors.add(i);
    }

    public List<Integer> getErrors() {
        return errors;
    }
};

流中的用法:

...
.exceptionally(ex -> {
                handler.accept(ex, i);
                return null;
            })

答案 3 :(得分:-1)

你可以用一种方法来做到这一点。

   List<CompletableFuture<Integer>> futures =
            list.stream()
                    .map(i -> yourFunction(i)).(Collectors.toList());

...

    public CompletableFuture<Integer> yourFunction(CompletableFuture<Integer> i){
...
    }

这不是很多练习但是有效