如何处理 Java 8 Stream 中的异常?

How to handle Exception in Java 8 Stream?

我有一种遍历列表并创建列表的方法。在这样做的同时,我正在调用一个方法 (createResult) 来给出结果,同时抛出 CustomException,我将其包装为 ResultClassException。但是我一直收到一条错误消息,提示未处理的异常。

我的代码:

 private  List<Result> getResultList(List<String> results) throws ResultClassException {
    List<Result> resultList = new ArrayList<>();
        results.forEach(
                (resultName) -> {
                    if (!resultRepository.contains(resultName)) {
                       try {
                           final Result result = createResult(resultName);
                           resultList.add(result);
                       } catch (CustomException e) {
                           throw new ResultClassException("Error",e);
                       }

                    } else {
                        resultList.add(resultRepository.get(resultName));
                        log.info("Result {} already exists.", resultName);
                    }
                }
        );
        return  Collections.unmodifiableList(resultList);
    }

有人能告诉我哪里做错了吗?

You can't handle a checked exception from inside of Streams

一种解决方法是从 createResult 中抛出 RuntimeException 或编写一个方法来包装 createResult,这将捕获并处理已检查的异常。

我不建议使用 RuntimeException,因为那会使您陷入糟糕的编码习惯。尝试在 getResultList(...) 的调用方法中处理 ResultClassException。

使用 Java 8 中的 lambda 表达式,您代表内部 classes。所以这个异常会在你的匿名内部class里面被抛出。 尝试在您要添加 throw new ResultClassException("Error",e)

的位置添加
Thread.getAllStackTraces()
  .keySet()
  .stream()
  .map(Thread::getStackTrace)
  .map(Arrays::asList)
  .forEach(list -> System.out.println(list.stream()
          .map(i -> i.toString())
          .collect(Collectors.joining("\n\t"))));

并查看调用它的线程。您将看到您的异常超出了您对 lambda 的预期范围。您会看到流正在创建许多线程,而您的异常不是您想要的线程的一部分。 你可以像这样包装你的方法: Java 8: How do I work with exception throwing methods in streams?

您的方法中可能有太多责任。你应该考虑把它分成一个只映射的方法和另一个收集它们的方法。

private List<Result> getResultList(List<String> names) throws ResultClassException {
  try {
    return names.stream()
        .map(this::getOrCreateResult)
        .collect(collectingAndThen(toList(), Collections::unmodifiableList));
  } catch (RuntimeException e) {
    if (e.getCause() instanceof CustomException) {
      throw new ResultClassException("Error", e.getCause());
    }
    throw e;
    // Or use Guava's propagate
  }
}

private Result getOrCreateResult(String name) {
  if (!resultRepository.contains(name)) {
    try {
      return createResult(name);
    } catch (CustomException e) {
      throw new RuntimeException(e);
    }
  } else {
    log.info("Result {} already exists.", name);
    return resultRepository.get(name);
  }
}

如果部分处理的流是可以接受的(不是错误的),一种优雅处理的好方法:

       List.of(1,2,3)
       .stream().map( entry-> {
            try {
              return Optional.of(new Object());
            } catch (Exception e) {
              log.error("error [{}] while transforming entry [{}]", e.getMessage(), entry, e);
              return Optional.empty();
            }
          }).filter(Optional::isPresent)
       .map(Optional::get)
       .collect(Collectors.toList());