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()
          }

        }
21
demandé sur Dzhu 2012-01-15 02:11:00

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 EitherS.)

19
répondu Rex Kerr 2012-01-15 22:40:10

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.

17
répondu Derek Wyatt 2012-01-14 22:44:22

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._)

0
répondu ChoppyTheLumberjack 2018-01-16 21:32:11