Practice Questions on Handling Errors in Asynchronous Code in Dart
- Create a function that simulates fetching user data. If the user ID is invalid, throw an exception. Handle the exception using a
try/catch
block when calling the function. - Write a program that demonstrates using
catchError
with aFuture
that may fail. If the Future fails, print an error message. - Implement a function that returns a
Future
which throws an exception after a delay. Useasync
andawait
to call this function, and handle the error appropriately. - Create a stream that yields numbers from 1 to 5, but throws an error when it reaches 3. Use the
onError
callback to handle the error when listening to the stream. - Write a function that takes a nullable integer and returns its reciprocal. If the integer is null or zero, throw an exception. Handle the exception using a
try/catch
block in the main function. - Implement a function that simulates a network request using a
Future
that either resolves with data or throws an error. Usethen
andcatchError
to handle the result and error. - Create a class that manages a list of items. Include a method to remove an item by index. If the index is out of bounds, throw an exception. Handle the exception when calling this method.
- Write a program that demonstrates global error handling using
runZonedGuarded
. Create a function that throws an exception, and catch the error in the zone. - Implement a method that reads data from a file asynchronously. If the file does not exist, throw an exception. Handle the exception using a
try/catch
block. - Create a function that fetches data from an API. If the API call fails, handle the error using both
try/catch
andcatchError
to show different handling approaches.
Solutions and Explanations
Fetching User Data
Future<String> fetchUserData(int userId) async { if (userId <= 0) { throw Exception('Invalid user ID'); } return 'User data for ID: $userId'; } void main() async { try { String data = await fetchUserData(-1); print(data); } catch (e) { print('Caught error: $e'); // Output: Caught error: Exception: Invalid user ID } }
Explanation: The
fetchUserData
function checks if the user ID is valid. If not, it throws an exception. In themain
function, we usetry/catch
to handle the exception.Using
catchError
with a FutureFuture<String> riskyOperation() { return Future.delayed(Duration(seconds: 1), () { throw Exception('Operation failed'); }); } void main() { riskyOperation().catchError((error) { print('Caught error: $error'); // Output: Caught error: Exception: Operation failed }); }
Explanation: The
riskyOperation
function simulates an operation that fails. Inmain
, we usecatchError
to handle the error without needing atry/catch
.Async Function with Exception
Future<void> throwError() async { await Future.delayed(Duration(seconds: 1)); throw Exception('An error occurred'); } void main() async { try { await throwError(); } catch (e) { print('Caught error: $e'); // Output: Caught error: Exception: An error occurred } }
Explanation: The
throwError
function simulates a delayed error. We await its completion inmain
, catching any exceptions thrown.Stream with Error Handling
Stream<int> numberStream() async* { for (int i = 1; i <= 5; i++) { await Future.delayed(Duration(seconds: 1)); if (i == 3) { throw Exception('Error at number 3'); } yield i; } } void main() { numberStream().listen( (number) => print(number), onError: (error) => print('Caught error: $error'), // Output: Caught error: Exception: Error at number 3 ); }
Explanation: The
numberStream
yields numbers from 1 to 5 but throws an error at 3. TheonError
callback inlisten
handles the exception.Nullable Integer Reciprocal
double reciprocal(int? number) { if (number == null || number == 0) { throw Exception('Cannot calculate reciprocal of null or zero'); } return 1 / number; } void main() { try { print(reciprocal(null)); } catch (e) { print('Caught error: $e'); // Output: Caught error: Exception: Cannot calculate reciprocal of null or zero } }
Explanation: The
reciprocal
function checks if the input is null or zero and throws an exception. The error is caught inmain
.Simulating a Network Request
Future<String> fetchFromNetwork() { return Future.delayed(Duration(seconds: 2), () { throw Exception('Network error'); }); } void main() { fetchFromNetwork().then((data) { print(data); }).catchError((error) { print('Caught error: $error'); // Output: Caught error: Exception: Network error }); }
Explanation: The
fetchFromNetwork
function simulates a network request that fails. We handle the error usingthen
andcatchError
.Managing a List of Items
class ItemManager { List<String> items = []; void removeItem(int index) { if (index < 0 || index >= items.length) { throw Exception('Index out of bounds'); } items.removeAt(index); } } void main() { ItemManager manager = ItemManager(); try { manager.removeItem(0); // This will throw an error } catch (e) { print('Caught error: $e'); // Output: Caught error: Exception: Index out of bounds } }
Explanation: The
ItemManager
class has a method to remove an item by index. If the index is invalid, it throws an exception, which is caught inmain
.Global Error Handling with Zones
void throwError() { throw Exception('An exception occurred in the zone'); } void main() { runZonedGuarded(() { throwError(); }, (error, stackTrace) { print('Caught error in zone: $error'); // Output: Caught error in zone: Exception: An exception occurred in the zone }); }
Explanation: In this example,
runZonedGuarded
captures any uncaught exceptions thrown within the zone, allowing for centralized error handling.Reading Data from a File
import 'dart:io'; Future<String> readFile(String path) async { if (!await File(path).exists()) { throw Exception('File not found'); } return await File(path).readAsString(); } void main() async { try { String data = await readFile('path/to/file.txt'); print(data); } catch (e) { print('Caught error: $e'); // Output: Caught error: Exception: File not found } }
Explanation: The
readFile
function checks if a file exists and throws an exception if it does not. This is handled inmain
using atry/catch
block.Fetching Data from an API
Future<String> fetchDataFromApi() { return Future.delayed(Duration(seconds: 1), () { throw Exception('API call failed'); }); } void main() async { try { String data = await fetchDataFromApi(); print(data); } catch (e) { print('Caught error using try/catch: $e'); // Output: Caught error using try/catch: Exception: API call failed } fetchDataFromApi().catchError((e) { print('Caught error using catchError: $e'); // Output: Caught error using catchError: Exception: API call failed }); }
Explanation: The
fetchDataFromApi
function simulates an API call that fails. We demonstrate error handling using bothtry/catch
andcatchError
to show different approaches.