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/catchblock when calling the function.
- Write a program that demonstrates using catchErrorwith aFuturethat may fail. If the Future fails, print an error message.
- Implement a function that returns a Futurewhich throws an exception after a delay. Useasyncandawaitto 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 onErrorcallback 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/catchblock in the main function.
- Implement a function that simulates a network request using a Futurethat either resolves with data or throws an error. UsethenandcatchErrorto 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/catchblock.
- Create a function that fetches data from an API. If the API call fails, handle the error using both try/catchandcatchErrorto 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 - fetchUserDatafunction checks if the user ID is valid. If not, it throws an exception. In the- mainfunction, we use- try/catchto handle the exception.
- Using - catchErrorwith a Future- Future<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 - riskyOperationfunction simulates an operation that fails. In- main, we use- catchErrorto handle the error without needing a- try/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 - throwErrorfunction simulates a delayed error. We await its completion in- main, 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 - numberStreamyields numbers from 1 to 5 but throws an error at 3. The- onErrorcallback in- listenhandles 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 - reciprocalfunction checks if the input is null or zero and throws an exception. The error is caught in- main.
- 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 - fetchFromNetworkfunction simulates a network request that fails. We handle the error using- thenand- catchError.
- 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 - ItemManagerclass has a method to remove an item by index. If the index is invalid, it throws an exception, which is caught in- main.
- 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, - runZonedGuardedcaptures 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 - readFilefunction checks if a file exists and throws an exception if it does not. This is handled in- mainusing a- try/catchblock.
- 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 - fetchDataFromApifunction simulates an API call that fails. We demonstrate error handling using both- try/catchand- catchErrorto show different approaches.