Excepciones marcadas y no
En definitiva, se necesitan excepciones para separar el escenario positivo (cuando todo va bien) del negativo (cuando ocurre un error y se interrumpe el escenario positivo). Esto es útil porque muy a menudo hay poca información en el código para manejar el error y necesita transmitir información sobre lo que sucedió anteriormente.
Por ejemplo, hay una función para leer un número de un archivo (o no un número, no importa):
String readStoredData(String id) throws FileNotFoundException, IOException {
File file = new File(storage, id + ".dat");
try (BufferedReader in = new BufferedReader(new FileReader(file))) {
return in.readLine();
}
}
Como puede ver, aquí no hay ningún código que decida qué hacer en caso de error. Y no está claro qué hacer: ¿terminar el programa, devolver "", nulo o algo más? Por lo tanto, las excepciones se declaran throws
y se manejarán en algún lugar de la persona que llama:
int initCounter(String name) throws IOException, NumberFormatException {
try {
return Integer.parseInt(readStoredData(name));
} catch (FileNotFoundException e) {
return 0;
}
}
Las excepciones en Java se dividen en marcadas y no marcadas. En este caso, IOException
está marcado: debe declararlo throws
y luego procesarlo en algún lugar, el compilador lo verificará. NumberFormatException
no verificable: su procesamiento permanece en la conciencia del programador y el compilador no lo controlará.
También hay un tercer tipo de excepción: errores fatales ( Error
), pero generalmente no tiene sentido manejarlos, por lo que no debe preocuparse por ellos.
, – , .
:
;
( – ) .
- , . .
Scala?
Scala: ( ), .
Try[T]
– , , . Scala:
def readStoredData(id: String): Try[String] =
Try {
val file = new File(storage, s"$id.dat")
val source = Source.fromFile(file)
try source.getLines().next()
finally source.close()
}
def initCounter(name: String): Try[Int] = {
readStoredData(name)
.map(_.toInt)
.recover {
case _: FileNotFoundException => 0
}
}
, , readStoredData
String
, Try[String]
– . Try Java – , .
:
(
Either[Error, T]
, );
happy-path , (
Try/get
for/map/flatMap
);
Java - , ( Java , ).
( Try[String]
– ). Option[T]
– , Future[T]
– ..
, – . / Java, ( ).
:
FileNotFoundException
,
IOException
–
:
def readStoredData(id: String): Option[Try[String]] = {
val file = new File(storage, s"$id.dat")
if (file.exists()) Some(
Try {
val source = Source.fromFile(file)
try source.getLines().next()
finally source.close()
}
)
else None
}
Option[Try[String]]
, , :
None
–
Some(Success(string))
–
Some(Failure(exception))
– ,
Try
. Java , null. .
La abundancia de tipos crea más ruido visual y, a menudo, requiere un código más complejo cuando se trabaja con varios efectos al mismo tiempo. Pero, a cambio, proporciona código autodocumentado y permite al compilador encontrar muchos errores.