Scala bloque enfin la fermeture / le rinçage des ressources
Existe - t-il un meilleur moyen de s'assurer que les ressources sont correctement libérées-une meilleure façon d'écrire le code suivant ?
val out: Option[FileOutputStream] = try {
Option(new FileOutputStream(path))
} catch {
case _ => None
}
if (out.isDefined) {
try {
Iterator.continually(in.read).takeWhile(-1 != _).foreach(out.get.write)
} catch {
case e => println(e.getMessage)
} finally {
in.close
out.get.flush()
out.get.close()
}
}
3 réponses
Quelque chose comme ça est une bonne idée, mais je ferais une méthode:
def cleanly[A,B](resource: => A)(cleanup: A => Unit)(code: A => B): Option[B] = {
try {
val r = resource
try { Some(code(r)) }
finally { cleanup(r) }
} catch {
case e: Exception => None
}
}
(notez que nous attrapons seulement une fois; si vous voulez vraiment un message imprimé dans un cas et pas l'autre, alors vous devez attraper les deux comme vous l'avez fait). (Notez également que je n'attrape que des exceptions; attraper Error
est généralement imprudent, car il est presque impossible de récupérer.) La méthode est utilisée comme ceci:
cleanly(new FileOutputStream(path))(_.close){ fos =>
Iterator.continually(in.read).takeWhile(_ != -1).foreach(fos.write)
}
Comme il renvoie une valeur, vous obtiendrez un Some(())
s'il a réussi ici (ce que vous pouvez ignorer).
Edit: pour le rendre plus général, je le ferais vraiment retourner un Either
à la place, donc vous obtenez l'exception. Comme ça:
def cleanly[A,B](resource: => A)(cleanup: A => Unit)(code: A => B): Either[Exception,B] = {
try {
val r = resource
try { Right(code(r)) } finally { cleanup(r) }
}
catch { case e: Exception => Left(e) }
}
Maintenant, si vous obtenez une Right
, tout s'est bien passé. Si vous obtenez un Left
, vous pouvez choisir votre exception. Si vous ne vous souciez pas de l'exception, vous pouvez utiliser .right.toOption
pour la mapper dans une option, ou simplement utiliser .right.map
ou autre pour fonctionner sur le résultat correct seulement s'il est là (comme avec Option
). (Pattern matching est un moyen utile de traiter Either
S.)
Jetez un oeil à Scala-ARM
Ce projet vise à être le projet D'incubateur Scala pour la gestion automatique des ressources dans la bibliothèque scala ...
... La bibliothèque Scala ARM permet aux utilisateurs d'assurer l'ouverture et la fermeture des ressources dans les blocs de code en utilisant la méthode" managed". La méthode" managed "prend essentiellement un argument de" tout ce qui a une méthode close ou dispose " et construit un nouvel objet ManagedResource.
Vous pouvez également le faire avec la Monade Tryclose paresseuse de Choppy.
val output = for {
fin <- TryClose(in)
fout <- TryClose.wrapWithCloser(new FileOutputStream(path))(out => {out.flush(); out.close();})
} yield wrap(Iterator.continually(fin.read).takeWhile(-1 != _).foreach(fout.get.write))
// Then execute it like this:
output.resolve
Plus d'infos ici: https://github.com/choppythelumberjack/tryclose
(juste être sûr d'importation tryclose._
et tryclose.JavaImplicits._
)