Esta guía es sólo para mostrar excepciones de usuario (Exception
). Los
errores del sistema (SystemError
) generalmente son fatales y nunca
se deberían atrapar.
Un uso común de las excepciones es la validación de los posiblemente inválidos datos introducidos por los usuarios. Una vez que se lanza una excepción, se recorre la pila hasta encontrar el primer gestor válido para la excepción lanzada.
try {
readText("dummyFile");
} catch (FileException e) {
// ...
}
Es posible tener varios bloques catch
. El bloque finally
siempre se ejecuta
independientemente de si ha ocurrido un error o no. Las excepciones se lanzan
mediante la palabra reservada throw
.
try {
throw new StringException("No pasarás.");
} catch (FileException e) {
// ...
} catch (StringException e) {
// ...
} finally {
// ...
}
Recuerda que el protector de ámbito (scope guard en inglés)
es en general una mejor solución que el patrón try - finally
.
Se pueden crear excepciones personalizadas fácilmente heredando de la
clase Exception
:
class UserNotFoundException : Exception {
this(string msg, string file = __FILE__, size_t line = __LINE__) {
super(msg, file, line);
}
}
throw new UserNotFoundException("D-Man is on vacation");
nothrow
El compilador de D puede asegurarse de que una función no cause efectos
colaterales catastróficos. Este tipo de funciones se marcan con la palabra
reservada nothrow
, lo que indica al compilador que tiene que prohibir
lanzar excepciones dentro de este tipo de funciones.
bool lessThan(int a, int b) nothrow {
writeln("mundo inseguro"); // esto puede lanzar excepciones, por lo que está prohibido
return a < b;
}
Hay que tener en cuenta que el compilador es capaz de inferir este tipo de atributos de forma automática para código generado a partir de plantillas.
std.exception
Es importante evitar usar assert
cuando se utiliza
contract programming (se verá en la próxima
sección) para validar la entrada de usuario, ya que tanto assert
como los
contracts se quitan cuando se compila la aplicación en modo release.
Por conveniencia, std.exception
proporciona enforce
,
que se puede usar como assert
, con la diferencia de que lanza excepciones
(Exception
) en lugar de AssertError
.
import std.exception : enforce;
float magic = 1_000_000_000;
enforce(magic + 42 - magic == 42, "Las matemáticas de coma flotante son divertidas");
// se lanzan excepciones personalizadas
enforce!StringException('a' != 'A', "Algoritmo que diferencia mayúsculas y minúsculas");
Independientemente de lo anterior, hay más cosas en std.exception
. Por ejemplo,
cuando un error no es fatal, este se puede coger mediante la función
collectException
.
import std.exception : collectException;
auto e = collectException(aDangerousOperation());
if (e)
writeln("La operación peligrosa ha fallado con ", e);
Para saber si se lanza una excepción en los tests, hay que usar
assertThrown
.