Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to handle checked exceptions in streams? #1009

Open
laurent-thiebaud-gisaia opened this issue Dec 18, 2018 · 5 comments
Open

How to handle checked exceptions in streams? #1009

laurent-thiebaud-gisaia opened this issue Dec 18, 2018 · 5 comments
Labels

Comments

@laurent-thiebaud-gisaia
Copy link

laurent-thiebaud-gisaia commented Dec 18, 2018

Suppose this example of code:

aStream.foreach(object -> consumeObjectMayThrowCheckedException())

This will not compile because of the checked exception. I think that the state of art, in functional programming, is to process the stream, then get the list of thrown exception to handle it (let's say in order to log it). I've been using the following code, that I don't like:

String errorMessage = mylist.stream().map(my ->

                Try.runWithCatch(() -> {
                    my.mayThrowCheckedException();

                }, CheckedException.class)
        )
                .filter(Try::isFailure)
                .map(t -> t.failureGet().orElse(new CheckedException("No exception")).getMessage())
                .collect(Collectors.joining(", "));

What would be the proper to achieve it? What is the state of the art using Cyclops?

Thanks.

@johnmcclean
Copy link
Member

Hi @laurent-thiebaud-gisaia ,

The IO monad in cyclops provides some support for checked exceptions. If you just wanted to log errors you could write something like this

IO.sync(myList)
  .checkedMap(My::mayThrowCheckedException)
  .forEach(System.out::println,System.err::println,()->System.out.println("Complete"));

In the forEach method we can provide consumers for each processed element, each error and the complete signal.

There is also a mapTry operator which can do the mapping directly to a Try, if we don't want to handle errors separately. mapTry doesn't directly support checked exceptions, but we can plugin the ExceptionSoftener for that :

import static com.oath.cyclops.util.ExceptionSoftener.softenFunction;

IO.sync(myList)
    .mapTry(softenFunction(My::mayThrowCheckedException))

Rather than use failureGet, if we convert our Try to en Either type we can call map on the 'left' side of the Either.

IO.sync(myList)
   .mapTry(softenFunction(My::mayThrowCheckedException))
   .map(Try::toEither)
   .map(e->e.mapLeft(Throwable::getMessage))

And to finish convert to a String

IO.sync(myList)
   .mapTry(softenFunction(My::mayThrowCheckedException))
   .map(Try::toEither)
   .map(e->e.mapLeft(Throwable::getMessage))
   .map(e->e.leftOrElse("No Exception"))
   .stream()
   .collect(Collectors.joining(","));

@laurent-thiebaud-gisaia
Copy link
Author

laurent-thiebaud-gisaia commented Dec 19, 2018

Hi,

I was able to make my code clearer using the either, thank you. However the following:

IO.sync(myList)
    .mapTry(softenFunction(My::mayThrowCheckedException))

doesn't compile because

non static method cannot be referenced from a static context java

@johnmcclean
Copy link
Member

It may depend on your classes. Is my a variable or a class?
I created a simple class called My.

static class My{
      public String mayThrowCheckedException() throws Exception{
            throw new RuntimeException("Erorr thrown");
      }
 }

List<My> myList = Arrays.asList(new My(), new My(), new My());

String errorMessage = IO.sync(myList)
                             .mapTry(softenFunction(My::mayThrowCheckedException))
                             .map(Try::toEither)
                             .map(e->e.mapLeft(Throwable::getMessage))
                             .map(e->e.leftOrElse("No Exception"))
                             .stream()
                             .collect(Collectors.joining(","));

This compiles, but probably doesn't quite match your classes.

@ayush-finix
Copy link

ayush-finix commented Mar 15, 2019

Does it not make sense to convert

.map(Try::toEither)
.map(e->e.mapLeft(Throwable::getMessage))
.map(e->e.leftOrElse("No Exception"))

to
.map(t -> t.fold(s -> "No Exception", e->e.getMessage()))

@johnmcclean
Copy link
Member

Yes, that is much neater

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants