2017-10-18 3 views
1

Après l'extrait de code fonctionne très bien:Problèmes avec Source.fromURL en essayant de le fermer en bloc finally

def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A = 
    try { f(closeable) } finally { closeable.close() } 

def loadDictionaryFromNet():List[String] = 
    using(Source.fromURL("http://www.mieliestronk.com/corncob_caps.txt", "UTF-8"))(_.getLines().toList) 

    val dictionary = loadDictionaryFromNet() filter(_.forall(_.isLetter)) 

Mais lorsque je tente de changer le type de Seq[String] comme ci-dessous:

def using[A, B <: {def close(): Unit}] (closeable: B) (f: B => A): A = 
    try { f(closeable) } finally { closeable.close() } 

def loadDictionaryFromNet():Seq[String] = 
    using(Source.fromURL("http://www.mieliestronk.com/corncob_caps.txt", "UTF-8"))(_.getLines().toSeq) 

    val dictionary = loadDictionaryFromNet() filter(_.forall(_.isLetter)) 

Ensuite, il lève l'exception suivante:

Exception in thread "main" java.io.IOException: stream is closed 
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.ensureOpen(HttpURLConnection.java:3348) 
    at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3373) 
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) 
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) 
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) 
    at java.io.InputStreamReader.read(InputStreamReader.java:184) 
    at java.io.BufferedReader.fill(BufferedReader.java:161) 
    at java.io.BufferedReader.readLine(BufferedReader.java:324) 
    at java.io.BufferedReader.readLine(BufferedReader.java:389) 
    ... 

Également lorsque je change de type en IndexedSeq cela fonctionne à nouveau.

Il "sent" que toSeq produit en fait un flux partiellement paresseux qui n'est pas consommé complètement immédiatement mais qui a un certain retard.

Pourriez-vous expliquer ce qui se passe sous le capot?

Répondre

1

En effet vous avez raison. Nous allons le suivre vers le bas à partir de Source.fromURL:

  1. Source.fromURL =>scala.io.BufferedSource
  2. BufferedSource.getLines =>BufferedLineIterator
  3. BufferedLineIterator.toSeq est appelé à partir scala.collection.TraversableOnce
  4. TraversableOnce implémente la méthode toSeq comme: def toSeq: Seq[A] = toStream
  5. La mise en œuvre de toStream est pris de la classe Iterator.

La mise en œuvre est la suivante:

def toStream: Stream[A] = 
    if (self.hasNext) Stream.cons(self.next(), self.toStream) 
    else Stream.empty[A] 

Ouf, tout un voyage. Oui, vous finissez par construire un flux qui est paresseux et donc vous obtenez l'exception que vous avez mentionnée dans la question.

+0

Merci. Des idées pour lesquelles 'TraversableOnce' utilise le' Stream' dans ce cas? J'ai d'abord pensé que cela avait probablement quelque chose à voir avec le fait que nous avons affaire à 'BufferedSource' qui a une part de lazyness cuite par principe. Mais je ne peux pas dire à coup sûr. –