Gestión de excepciones y errores

Todas las excepciones en Dart son excepciones no comprobadas: no hace falta declarar en la función el tipo que se lanza, y no es obligatorio capturarlas.

Se dividen en dos tipos:

  • Exception:Errores previsibles de la lógica de negocio (problemas de formato, parámetros inválidos… Se recomienda capturarlos y tratarlos).
  • Error:Errores fatales del programa (incompatibilidades de tipo, puntero nulo, métodos no implementados… Generalmente no se capturan).

Se puede lanzar cualquier objeto que no sea null con la palabra reservada throw. En proyectos estructurados, solo se lanzan subclases de Exception/Error.

Cualquier excepción no capturada finaliza el isolate actual y provoca el cierre inesperado de la aplicación.

throw: lanzar una excepción

1. Lanzar excepciones nativas del sistema

void main() {
  // Excepción de formato
  throw FormatException("Se requiere al menos un segmento de datos");
}
Lenguaje del código: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
FormatException: Descripción del error
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:3:3)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Lenguaje del código: PHP (php)

Este código lanza una excepción predefinida con un mensaje personalizado que se mostrará al ejecutar el programa. A simple vista puede parecer inútil, pero el lanzamiento de excepciones es fundamental en el desarrollo. Por ejemplo, en el registro de usuarios validamos los datos introducidos: si no cumplen las reglas, lanzamos una excepción inmediatamente para interrumpir el flujo y avisar al usuario, evitando que datos incorrectos entren al sistema y manteniendo la integridad de la información.

2. Lanzar cualquier objeto

No recomendado para entornos de producción

void main() {
  throw "Texto descriptivo del error!";
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
Texto descriptivo del error!
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:2:3)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Lenguaje del código: PHP (php)

3. Usar throw dentro de una función flecha (throw es una expresión)

class Point {}
void distanceTo(Point other) => throw UnimplementedError("Este método no está implementado");

void main() {
  distanceTo(Point());
}
Lenguaje del código: JavaScript (javascript)

III. Capturar excepciones con try /on/catch

Diferencias de sintaxis

  • on TipoExcepción:Solo coincide con excepciones del tipo indicado, no se puede acceder al objeto de excepción.
  • catch(e):Captura todas las excepciones, la variable e almacena la instancia de la excepción.
  • catch(e, s):e = objeto de excepción, s = información de pila de llamadas StackTrace.

1: Capturar un solo tipo de excepción con on


// Definir una clase de excepción personalizada que implementa Exception
class OutOfLlamasException implements Exception {}

// Función que lanza la excepción personalizada anterior
void breedMoreLlamas() {
  throw OutOfLlamasException();
}

void buyMoreLlamas() {
  print("Se ha ejecutado la función buyMoreLlamas");
}

void main() {
  try {
    breedMoreLlamas(); // Llamar a la función con código de riesgo
  } on OutOfLlamasException {
    buyMoreLlamas(); // Se ejecuta si se captura OutOfLlamasException
  }
}Lenguaje del código: Dart (dart)

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Se ha ejecutado la función buyMoreLlamasLenguaje del código: CSS (css)
try  {
    // Código que puede generar errores
} on ClaseExcepción {
   // Código que se ejecuta al capturar el error
}Lenguaje del código: Dart (dart)

try on es una sintaxis específica para capturar excepciones por tipo.

2: Capturación jerárquica con múltiples ramas

Las coincidencias más precisas se ejecutan primero

class OutOfLlamasException implements Exception {}

void breedMoreLlamas() {
  throw FormatException("Error de formato de datos");
}

void main() {
  try {
    breedMoreLlamas();
  }
  // 1. Coincidencia exacta con la excepción personalizada
  on OutOfLlamasException {
    print("Se ha producido el error OutOfLlamasException");
  }
  // 2. Capturar todas las subclases de Exception
  on Exception catch (e) {
    print("Excepción de negocio común:$e");
  }
  // 3. Rama de respaldo para Error y cualquier otro objeto lanzado
  catch (e) {
    print("Error grave desconocido:$e");
  }
}
Lenguaje del código: Dart (dart)

Salida:Excepción de negocio común:FormatException: Error de formato de datos

Se pueden usar varios bloques on para capturar tipos de Exception por separado, y un catch final para cubrir todos los casos restantes.

3: Capturar excepción + imprimir pila de llamadas StackTrace

void main() {
  try {
    int a = null;
    print(a + 1);
  } catch (e, stack) {
    print("Mensaje de excepción:$e");
    print("Pila de llamadas completa:\n$stack");
  }
}
Lenguaje del código: Dart (dart)

Este código no solo muestra el mensaje de error, sino también toda la ruta de llamadas de funciones para facilitar la depuración.

D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:3:13: Error: A value of type 'Null' can't be assigned to a variable of type 'int'.
    int a = null;Lenguaje del código: PHP (php)

IV. rethrow relanzar excepción

Tratar parcialmente y volver a lanzar hacia arriba

Función: la función actual ejecuta parte de la lógica de recuperación y luego pasa la excepción al llamante para que la trate adicionalmente.

A veces no basta con tratar el error solo en la función actual, sino que debemos notificar también al código llamante para que realice acciones complementarias.

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // true no admite incremento, genera error en tiempo de ejecución
  } catch (e) {
    print("Tratamiento local en misbehave:${e.runtimeType}");
    rethrow; // Volver a lanzar para que el try exterior lo capture
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print("Tratamiento final en main:${e.runtimeType}");
  }
}
Lenguaje del código: Dart (dart)

Flujo de ejecución:

Tratamiento local en misbehave:NoSuchMethodError
Tratamiento final en main:NoSuchMethodError
Lenguaje del código: PHP (php)

El código anterior ejecuta la lógica de tratamiento de errores tanto en la función misbehave como en main.

V. Bloque finally final

Se ejecuta obligatoriamente haya error o no

Dos escenarios de uso:

  1. Solo try + finally: no se captura la excepción, el programa se cierra después de ejecutar finally
  2. try + catch + finally: primero tratar el error y luego ejecutar finally (destinado a liberar recursos)

1: try + finally

void cleanLlamaStalls() => print("Limpieza de recursos, bloque obligatorio de respaldo");
void breedMoreLlamas() => throw Exception("Se ha producido un error");

void main() {
  try {
    breedMoreLlamas();
  } finally {
    cleanLlamaStalls();
  }
}
Lenguaje del código: Dart (dart)

Aunque se ejecuta el código de limpieza, la excepción no capturada termina cerrando el programa.

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Limpieza de recursos, bloque obligatorio de respaldo
Unhandled exception:
Exception: Se ha producido un error
#0      breedMoreLlamas (file:///D:/dartdemo/firstdart/bin/firstdart.dart:2:27)
#1      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:5)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#3      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Lenguaje del código: PHP (php)

2: try + catch + finally

Sintaxis estándar para liberar recursos, por ejemplo cerrar archivos abiertos

void cleanLlamaStalls() => print("Cerrar archivos / liberar recursos ocupados");
void breedMoreLlamas() => throw FormatException("Fallo al analizar datos");

void main() {
  try {
    breedMoreLlamas();
  } catch (e) {
    print("Excepción capturada:$e");
  } finally {
    cleanLlamaStalls();
  }
}
Lenguaje del código: Dart (dart)

Orden de ejecución: ocurre excepción → catch trata el error → se ejecuta finally

Resultado de ejecución

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Excepción capturada:FormatException: Fallo al analizar datos
Cerrar archivos / liberar recursos ocupados

VI. assert aserción

Solo activo en desarrollo y depuración, deshabilitado totalmente en producción

assert(condición booleana, [mensaje de error opcional])

Si la condición es false lanza AssertionError. En compilaciones de producción se ignora completamente sin coste de rendimiento.

1: Aserción básica

void main() {
  String? text;
  int number = 120;
  String url = "http://foxdevelop.com";

  assert(text != null); // Comprobar que no es nulo
  assert(number < 100); // Validar rango numérico
  assert(url.startsWith("https")); // Verificar protocolo de enlace
}
Lenguaje del código: JavaScript (javascript)

Si ejecutas este código tal cual no se muestra ninguna salida!

Las aserciones están desactivadas por defecto, hay que activarlas mediante un parámetro de ejecución, ver abajo.

2: Definir mensaje de error personalizado

void main() {
  String url = "http://test.com";
  assert(
    url.startsWith("https"),
    "El enlace $url debe empezar por https",
  );
}
Lenguaje del código: JavaScript (javascript)

Podemos redactar libremente el mensaje que aparece cuando falla la aserción.

Cómo activar las aserciones

  1. Modo Debug de Flutter: las aserciones están activadas por defecto
  2. Ejecución con comando dart: dart --enable-asserts nombrearchivo.dart
  3. Compilación para producción: todo el código de aserciones se elimina, sin pérdida de rendimiento
D:\dartdemo\firstdart\bin>dart --enable-asserts firstdart.dart
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Lenguaje del código: PHP (php)

Tanto dart run como el comando simple dart tienen las aserciones desactivadas por defecto, hay que añadir el flag --enable-asserts:

Comando de ejecución

dart run --enable-asserts main.dartLenguaje del código: CSS (css)

Si tu terminal ya está en la raíz del proyecto puedes ejecutar la versión abreviada directamente:

Comando de ejecución:

dart run --enable-asserts

dart run:Ejecutar código fuente Dart directamente, para desarrollo y depuración

dart nombrearchivo:Sintaxis simplificada para ejecutar un solo archivo

dart compile exe:Compilar a ejecutable independiente, el binario generado siempre tiene assert desactivado

Los archivos Dart se encuentran en la carpeta bin del proyecto. Puedes entrar en bin para ejecutar el archivo individual o subir un nivel a la raíz del proyecto para ejecutar todo el proyecto completo.

dart run –enable-asserts

A continuación se muestran dos formas: ejecutar directamente desde la carpeta bin y ejecutar desde la raíz del proyecto padre.

D:\dartdemo\firstdart\bin>dart --enable-asserts firstdart.dart
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)

D:\dartdemo\firstdart\bin>dart run
Building package executable...
Built firstdart:firstdart.

D:\dartdemo\firstdart\bin>cd ..

D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Lenguaje del código: PHP (php)

Si la condición de la aserción es true no se lanza ninguna excepción.

Modifica el código ejemplo: cambia http por https en la url, sustituye text != null por text == null y asigna 99 a number

void main() {
  String? text;
  int number = 99;
  String url = "https://foxdevelop.com";

  assert(text == null); // Comprobación de nulo
  assert(number < 100); // Validación de rango numérico
  assert(url.startsWith("https")); // Verificación de protocolo URL
}Lenguaje del código: Dart (dart)

Al volver a ejecutar no se produce ninguna excepción.

D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.Lenguaje del código: CSS (css)

VII. Ejemplo completo

void cleanResource() => print("finally: liberar recursos ocupados");

void testError() {
  try {
    int num = 150;
    assert(num < 100, "El número debe ser menor que 100");
    throw FormatException("Formato de datos inválido");
  } on FormatException catch (e) {
    print("Capturada excepción de formato:$e");
    rethrow;
  } finally {
    cleanResource();
  }
}

void main() {
  try {
    testError();
  } catch (e) {
    print("main captura la excepción relanzada:$e");
  }
}
Lenguaje del código: PHP (php)

Resultado de ejecución

D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.
finally: liberar recursos ocupados
main captura la excepción relanzada:'file:///D:/dartdemo/firstdart/bin/firstdart.dart':
 Failed assertion: line 6 pos 12: 'num < 100': El número debe ser menor que 100Lenguaje del código: PHP (php)

Ejemplo completo del flujo entero de gestión de excepciones y errores

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *