5

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 in 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

If .recover is not the right method please suggest alternatives where I can catch my one specific Exception but not Throwable since it catches all exceptions and errors.

user1870400
  • 6,028
  • 13
  • 54
  • 115

1 Answers1

3

It's quite easy to explain. You method - it isn't stated explicitly but I assume so based on error message returns void. Since recover also must return a value - needed for further processing - compatible with the type returned from methods it wraps, it has to return Void, so:

So the code will be:

Try
   .run(this::sayHello)
   .recover(MyAppRuntimeException.class, e -> {
      log.error("Error occured: {}", e.getMessage());
      return null;
   });

Have a look at the docs.

EDIT

After discussion in comments it turned out that recover is not what is needed. This function is used to provide a recovery value, not to log a statement, hence onFailure + instanceof (instead of pattern matching) seems to do the job:

Try
   .run(this::sayHello)
   .onFailure(throwable -> {
      if (throwable instanceof MyAppRuntimeException) {
         log.error("Error occured: {}", throwable.getMessage());
      } else {
         throw new RuntimeException(throwable);
      }
   })
Opal
  • 81,889
  • 28
  • 189
  • 210
  • 1
    I was looking for a cleaner way if not recover some other API call but I couldn't find anything in the docs and. yes sayHello() returns void. If I have to return null for every log statement I might as well just use the Java's regular try/catch since it would look more cleaner – user1870400 Oct 16 '17 at 19:27
  • @user1870400, a cleaner way would be to use a `onFailure` method. It accepts an instance of `Consumer` hence to need to return anything. – Opal Oct 16 '17 at 21:00
  • 1
    onFailure method looks like it will accept throwable. I dont want to catch throwable since it will catch all Exceptions and Errors. I only want to catch MyAppRuntimeException. Please clarify – user1870400 Oct 16 '17 at 21:18
  • Yes you're right. Another way to do is to use pattern matching which might be an obverkill in this simple case. Recover is not meant to log a statement but to provide a reocvery value. `onFailure` is what you need - you can always use `instanceof`. – Opal Oct 16 '17 at 21:34
  • I think you made a point on recover method. Could you please update the answer using onFailure and instanceOf ? so I can accept the answer. It would also help me. Thanks much! IF the instance of check fails I would like exception to be thrown as normal – user1870400 Oct 16 '17 at 21:37
  • 1
    What would happen if `throwable instanceof MyAppRuntimeException` check fails? – user1870400 Oct 16 '17 at 21:46
  • say I have some other exception other than MyAppRuntimeException and say the check `throwable instanceof MyAppRuntimeException` fails would that exception is thrown? or I will catch all exceptions and errors ? – user1870400 Oct 16 '17 at 21:48
  • I guess it'd be even faster if you'd tried it yourself. If this check fails nothing happens, since there's not `else`. All exceptions will be passed to that method but and action will be executed for `MyAppRuntimeException` only. – Opal Oct 17 '17 at 07:26
  • 1
    yeah but I would want as per my question is that if the check fails it should throw as normal. since I am only trying to catch one specific exception and throw everything else. In the above example you provided I can indeed log when the `MyAppRuntimeException` occurs but I will also remain silent if there is any other Exception. I don't want to remain silent if there is any other Exception or error. sounds like Vavr is not mature enough to handle exceptions! – user1870400 Oct 17 '17 at 07:57
  • Indeed vavr has some limitations however I claim it's mature enough and very popular. This is for some reasons. What are you trying to achieve? `onFailure` is just a consumer you can log any exceptions there. At the beginning you wanted the single one, now you complain it logs the only one. I don't get it. – Opal Oct 17 '17 at 08:00
  • 1
    ok I am not sure what is not clear to you. But my goal is simple. I want to log when I get a specific exception that is "MyAppRuntimeException" and if there is any other RuntimeException or an Error that occurs I want them to be thrown like any other Java program. In the example you provided it will remain silent since it is catching Throwable. is that clear enough? – user1870400 Oct 17 '17 at 08:06
  • It looks that you're missing the basic understanding of how vavr works :( `onFailure` works like `peek` - just enables you to see what's going there inside the flow. If exception is thrown or not at **later** stage is an another matter. – Opal Oct 17 '17 at 08:18
  • True I dont understand how it works! And I don't understand even now. Ok say I have MyAppRuntimeException and DivisionByZeroException. now I want to log when `MyAppRuntimeException` occurs and just throw if DivisionByZeroException or any other Exception occurs. so onFailure gets Invoked when there is an Exception in the program correct ?! If so, I would inspect and see what exception that is. if it is `MyAppRuntimeException` I log it and if it is DivisionByZeroException I just want to throw that Exception but not remain silent. – user1870400 Oct 17 '17 at 08:26
  • Then leave the code as is and add `get` (or any other method that resolves the chain) at the end - which is *functional* but will throw an exception if it occurs. – Opal Oct 17 '17 at 08:30
  • @user1870400, instead of calling get you can throw exception from else branch, however you need to wrap it into RuntimeException. – Opal Oct 17 '17 at 16:37
  • got it! will use explicitly use throw like you showed but you can see this is a big limitation of Vavr library. I don't believe Vavr good Api call for exception handling since everything is modeled around Throwable's. There are also other people facing the same issue. https://github.com/vavr-io/vavr/issues/2137 – user1870400 Oct 17 '17 at 19:37
  • That may be true, however vavr also assumes (I suppose) that yon won't be throwing an exception, but processing it if it occurs. – Opal Oct 17 '17 at 19:52
  • yes I don't want be catching and throwing exceptions this way. this is indeed a hack because of the poor interface design by Vavr in this aspect. you can take a look at that ticket and see what other people had already suggested. They want `` instead of ` Extends Throwable>`. That makes a huge difference – user1870400 Oct 17 '17 at 21:31
  • with Cyclops library I can easily do the following for my above question `Try.catchExceptions(MyAppRuntimeException.class) .try(() -> sayHello()) .onFail(MyAppRuntimeException.class, log.error("Error occured: {}", e.getMessage()))` Although I like Vavr than Cyclops. I think Cyclops has better exception handling than Vavr at this time. – user1870400 Oct 17 '17 at 21:34
  • If `throwable` will be checked exception, your code will rethrow it as unchecked, which is not good code style – chill appreciator Jan 29 '20 at 14:36
  • Why? I see that nowadays developers tend to avoid checked exceptions. – Opal Jan 30 '20 at 06:54