Exceptions vérifiées et non
En bref, des exceptions sont nécessaires pour séparer le scénario positif (quand tout va bien) du négatif (lorsqu'une erreur se produit et que le scénario positif est interrompu). Ceci est utile car très souvent, le code contient peu d'informations pour gérer l'erreur et vous devez transmettre des informations sur ce qui s'est passé ci-dessus.
Par exemple, il existe une fonction pour lire un nombre à partir d'un fichier (ou pas un nombre, peu importe):
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();
}
}
Comme vous pouvez le voir, il n'y a pas de code ici qui décide de ce qu'il faut faire en cas d'erreur. Et on ne sait pas quoi faire - terminer le programme, retourner "", null ou autre chose? Par conséquent, les exceptions sont déclarées throws
et seront traitées quelque part sur l'appelant:
int initCounter(String name) throws IOException, NumberFormatException {
try {
return Integer.parseInt(readStoredData(name));
} catch (FileNotFoundException e) {
return 0;
}
}
Les exceptions en Java sont divisées en cochées et non cochées. Dans ce cas, IOException
il est vérifié - vous devez le déclarer throws
et le traiter quelque part, le compilateur le vérifiera. NumberFormatException
invérifiable - son traitement reste sur la conscience du programmeur et le compilateur ne vous contrôlera pas.
Il existe également un troisième type d'exception - les erreurs fatales ( Error
), mais elles n'ont généralement pas de sens à gérer, vous ne devriez donc pas vous en préoccuper.
, – , .
:
;
( – ) .
- , . .
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. .
L'abondance de types crée plus de bruit visuel et nécessite souvent un code plus complexe lorsque vous travaillez avec plusieurs effets en même temps. Mais en retour, il fournit du code auto-documenté et permet au compilateur de trouver de nombreuses erreurs.