Dart What is the difference between throw and rethrow? - flutter

It might be obvious, but I still fail to understand the difference between throw and rethrow and when do either of those should be used?

According to Effective Dart:
If you decide to rethrow an exception, prefer using the rethrow statement instead of throwing the same exception object using throw. rethrow preserves the original stack trace of the exception. throw on the other hand resets the stack trace to the last thrown position.
The biggest difference is the preservation of the original stack trace.
They provided 2 examples to show the intended usage:
Bad:
try {
somethingRisky();
} catch (e) {
if (!canHandle(e)) throw e;
handle(e);
}
Good:
try {
somethingRisky();
} catch (e) {
if (!canHandle(e)) rethrow;
handle(e);
}

Related

what's does rethrow do in dart, and how it differ than throw [duplicate]

This question already has an answer here:
Dart What is the difference between throw and rethrow?
(1 answer)
Closed 4 months ago.
I know what does throw keyword dp in a dart / flutter code, but I don't seem to understand the rethrow
I see it in examples like :
void misbehave() {
  try {
// code
  } catch (e) {
    rethrow;
  }
}
what does exacltly rethrow do in that code, I don't seem to understand the concept behind it from the dart documentation.
any informations will be pricefull
I want to know what rethrow does in my code
In simple words
The throw is used to throw a new exception.
rethrow throws the expectation that it received from the other function call function.
Example
Suppose use have this function
void divideByZero(){
try{
0/0
} catch (error){
//You will receive the exception here.
//You can perform some operations here or throw the exception if the operations defined here can not handle that exception.
// But it won't preserve the stack trace of the original exception.
//It's better to use rethrow if you have this kind of case.
}
}

Is there any practical difference between throw Exception('message') vs throw 'message' in Flutter?

Is there any practical difference between using:
throw Exception('message');
vs
throw 'message';
When I want to throw an error in flutter?
throw 'message' throws a String.
Callers trying to catch it either would need to do:
try {
throw 'message';
} on String catch (s) {
...
}
or would need to use a blanket, untyped catch clause (which isn't recommended). Doing this would be very unusual and would not be behavior callers would expect. There is an only_throw_errors lint to warn about this.
throw Exception('message'); throws a constructed Exception object. That's far more typical.

Refactor catch statements

We have many try-catch blocks in our code handling the exceptions of the api calls. Since most of the catch blocks are identical we want to refactor them and only them (because the try blocks should stay in the place they are). How is this possible in Flutter?
Example code:
try {
_userData = apiService.call("user_data");
} on ResourceNotFoundException {
handleResourceNotFoundException();
} on NetworkException {
handleNetworkException();
}
The best solution I found is using a general catch, fit everything into a handleException function, and in there rethrow the exception again.
try {
_userData = apiService.call("user_data");
} on catch (e) {
handleException(e);
}
void handleException(e) {
try {
throw e;
} on ResourceNotFoundException {
handleResourceNotFoundException();
} on NetworkException {
handleNetworkException();
}
}
This way it is possible to reuse the exception handling logic and also extend it.
You should add some abstraction to your API call, meaning you should add a function that takes in the API call you are trying to call as a parameter and surround it with a try-catch block and handle all your exceptions there.
This way you have separated your API calls logic from handling exceptions.

Thrown exception does not get catched in `on` clause (type seems to be wrong)

I have an asynchronous method with a try catch block and it calls another async method that throws. My problem is that the thrown exception is not catched in the catch block.
Future savePlayer(Player player) async {
try {
var store = await SharedPreferences.getInstance();
await store.setString(_playerId, jsonEncode(player.toJson())); // exception in player.toJson() "NoSuchMethod"
} on Exception catch (err) {
throw LocalStorageException( // no catch here
message: TextConstants.exception.localStorageSaveException,
hint: TextConstants.exception.localStorageSaveExceptionHint,
originalExceptionText: err.toString());
} catch (err) {
throw LocalStorageException( // catch here, but why?
message: TextConstants.exception.localStorageSaveException,
hint: TextConstants.exception.localStorageSaveExceptionHint,
originalExceptionText: err.toString());
}
}
If I remove on Exception and just use the catch, then it works. This would be a valid workaround for me. But as I am using the Effective Dart coding rules I get a warning when omitting the on clause.
https://dart-lang.github.io/linter/lints/avoid_catches_without_on_clauses.html
What is the correct way to catch ANY exception in a catch block with an on clause?
on Exception catches objects of type Exception.
What is being thrown is a NoSuchMethodError, which is an Error. Errors are not Exceptions (nor vice-versa).
Dart distinguishes between runtime errors and logical errors (programmer errors). Runtime errors should derive from Exception; logical errors should derive from Error.
Effective Dart discourages catching Error. They usually represent a programming mistake that could have and should have been avoided (e.g. calling a non-existent function).

Best way to catch "Sequence contains no elements"

If Single doesn't find the element you're expecting to exist then it throws an InvalidOperationException. Only trouble is that other things result in this exception too. For example an EF Code First model being out of date.
I've tried to narrow it down by checking the exception message. However this could change and I'd be none the wiser. Is there a better way of catching this problem?
try
{
return DbSet.Single(filter);
}
catch (InvalidOperationException exc)
{
if (exc.Message == "Sequence contains no elements")
{
throw new UserNotFoundException();
}
throw;
}
Use .FirstOrDefault() instead. Then check to see if the result is null. If it is, the user wasn't found.