4

I have a method where I am traversing through a List and creating List. While doing so, I am calling a method(createResult) to will give a Result also throws CustomException which I am wrapping as ResultClassException. But I keep getting an error saying Unhandled Exception.

My Code :

 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);
    }

Can Someone tell what I am doing wrong?

Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
user3407267
  • 1,524
  • 9
  • 30
  • 57
  • 4
    Either `ResultClassException` is not a subclass of `RuntimeException` or `resultRepository.get(resultName)` throws a checked exception. You can't throw checked exceptions from within `forEach`'s lambda, as this lambda would not correspond to the `Consumer` functional interface. – fps Apr 13 '17 at 04:45
  • 2
    I don't see any streams in your code, just a `forEach`. Why not use a regular `for` loop? – shmosel Apr 13 '17 at 07:55
  • Does this answer your question? [Java 8: Lambda-Streams, Filter by Method with Exception](https://stackoverflow.com/questions/19757300/java-8-lambda-streams-filter-by-method-with-exception) – Vadzim Mar 05 '20 at 20:22

5 Answers5

7

You probably have too many responsibilities in your method. You should think about splitting it into a method that only maps and another one that gathers them.

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);
  }
}
Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137
1

I wouldn't suggest using RuntimeException as that would drive you into poor coding practice. Try to handle ResultClassException in the calling method of getResultList(...).

msuper
  • 171
  • 1
  • 2
1

A good way to process gracefully if partially processed stream is acceptable(not wrong):

       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());
Abhinav Atul
  • 601
  • 6
  • 14
0

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

One workaround can be to throw a RuntimeException from createResult or write a method to wrap createResult which will catch and handle the checked exception.

Community
  • 1
  • 1
santosh-patil
  • 1,540
  • 1
  • 15
  • 29
0

With the lambda expressions in Java 8 you are representing inner classes. So the exception will be thrown inside your anonymous inner class. try to add that where you are adding your the 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"))));

and see the thread that is calling it. You will see that your exception is out of the scope you expected with the lambdas. You will see that the stream is creating many threads and your exception is not part of the thread you want. You can wrap your method like that: Java 8: How do I work with exception throwing methods in streams?

Matthieu
  • 2,736
  • 4
  • 57
  • 87
strash
  • 1,291
  • 2
  • 15
  • 29