Vavr: Unable to catch a specific runtime exception using Vavr library?

Created on 16 Oct 2017  路  12Comments  路  Source: vavr-io/vavr

I am trying to catch a specific runtime exception (so not throwable) and just log it (log.error has a void return type). What is the simplest way to do this vavr?

```
try {
sayHello();
} catch (MyAppRuntimeException ex) {
log.error("Error occured"); // log.error returns void not Void so I couldn't find a suitable method in Vavr library
}

I have tried
Try.run(() -> sayHello())
   .recover(MyAppRuntimeException.class, ex->log.error(Error occured: {}, ex.getMessage()));

```

I get Bad return type void cannot be converted to Void

feature 芦vavr-core禄

Most helpful comment

@kant111, @hamnis

Can you describe why it isn't a viable solution ?

Maybe I was too fast closing the issue. I don't like to add special cases for void or primitive types. It will blow up the API unnecessarily. Especially it seems odd to _recover_ literally _nothing_.

What do you all think about the following?

    default <X extends Throwable> Try<T> onFailure(Class<X> exception, Consumer<? super X> action) {
        Objects.requireNonNull(exception, "exception is null");
        Objects.requireNonNull(action, "action is null");
        if (isFailure() && exception.isAssignableFrom(getCause().getClass())) {
            action.accept((X) getCause());
        }
        return this;
    }
  • It is more general than recoverUnit
  • It can be applied to all underlying value types, not only Void
  • It is syntactic sugar for onFailure(Consumer), that has to explicitly check the type within the given Consumer
  • It can be applied fluently because it isn't a static method

All 12 comments

In your case the second parameter of Try::recover call is Function<MyAppRuntimeException, Void>. Try this:

Try.run(() -> sayHello())
        .recover(MyAppRuntimeException.class, ex -> {
            System.out.println(ex.getMessage());
            return null;
        });

@ruslansennov Sure, but is there any cleaner way? else I had to return null for lot of my log statements. I have also looked into the .onFailure method and it looks like it is going to catch throwable in which case it will catch all exceptions and errors but I only want to catch one exception which is MyAppRuntimeException. And if there are other RuntimeExceptions that occur then I want them to be thrown as any other java program does but not go silent by catching Throwable.

the only value that can exist for Void is null. there is way to instantiate Void.

there could be an overload that accept a Consumer<E>, and handles this interally.

@hamnis Consumer<E> This is all we are looking for

@kant111 and @hamnis this is idiosyncratic Java. In functional parlance, it isn't a function if it doesn't return anything. In Java, that's ok. It's a consumer

Well. because of the Java typesystem this is not really correct. Since we cannot infer the inner type the Try is supposed to have, it will have to be a new method not an overload. Changing the return type to Try<Void> is probably not what you expected.

static <X extends Throwable> Try<Void> recoverUnit(Try<Void> tried, Class<X> exception, Consumer<? super X> f) {
        return tried.recover(exception, ex -> {
            f.accept(ex);
            return null;
        });
    }

I know, this is really a pain in the ass in Java but adding overloads (and primitive specializations in general) isn't a viable solution for us.

With primitive generics all will be fine (fingers crossed).

@danieldietrich Can you describe why it isn't a viable solution ?

@kant111, @hamnis

Can you describe why it isn't a viable solution ?

Maybe I was too fast closing the issue. I don't like to add special cases for void or primitive types. It will blow up the API unnecessarily. Especially it seems odd to _recover_ literally _nothing_.

What do you all think about the following?

    default <X extends Throwable> Try<T> onFailure(Class<X> exception, Consumer<? super X> action) {
        Objects.requireNonNull(exception, "exception is null");
        Objects.requireNonNull(action, "action is null");
        if (isFailure() && exception.isAssignableFrom(getCause().getClass())) {
            action.accept((X) getCause());
        }
        return this;
    }
  • It is more general than recoverUnit
  • It can be applied to all underlying value types, not only Void
  • It is syntactic sugar for onFailure(Consumer), that has to explicitly check the type within the given Consumer
  • It can be applied fluently because it isn't a static method

@danieldietrich That looks good to me (As long as we are not catching throwable's I think we are good) ! It might even solve https://github.com/vavr-io/vavr/issues/2137

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ronanM picture ronanM  路  3Comments

roookeee picture roookeee  路  5Comments

yarulan picture yarulan  路  5Comments

carnott-snap picture carnott-snap  路  4Comments

Vivek-Patil picture Vivek-Patil  路  3Comments