I have the following piece of code that I am trying to enhance:
I am using the java.nio.file
package to represent a directory or a file as a Path
.
So here goes:
import java.nio.file.{Paths,DirectoryStream,Files,
Path,DirectoryIteratorException}
val path: Path = Paths.get(directoryPath)
var directoryStream: Option[DirectoryStream[Path]] = None
// so far so good
try {
directoryStream = Some(Files.newDirectoryStream(pathO))
// this is where i get into trouble
def getMeDirStream: DirectoryStream[Path] =
if (!directoryStream.isEmpty && directoryStream.isDefined)
getMeDirStream.get
else
None
// invoke the iterator() method of dstream here
}
The above piece of code will not compile because I do not know what to return in the else, and right now, for the life of me, I can only come up with None
, which the compiler simply does not like and I would like to learn what should be its replacement.
I want this example to be a learning lesson of Option
and Some
for me.
Okay, this is where I choke. I would like to check if the directoryStream
is not empty and is defined, and then if this is the case, I would like to invoke getMeDirStream.get
to invoke the iterator()
method on it.
The API for Option
tells me that invoking the get()
method could result in a java.util.NoSuchElementException
if the option is empty.
If the directoryStream is empty I want to return something and not None, because IntelliJ is telling me that "Expression of type None.type
doesn't conform to expected type DirectoryStream[Path]
".
Now, I am being all naive about this.
I would like to know the following:
What should I return in the else
other than None
?
Should I wrap the getMeDirStream.get
in a try-catch with a java.util.NoSuchElementException
, even though I am checking if the directoryStream
is empty or not.?
What is the purpose of a try-catch in the getMeDirStream.get
, if there is indeed such a need?
How can I clean up the above piece of code to incorporate correct checks for being isDefined
and for catching appropriate exceptions?
Once I know what to return in the else (and after putting in the appropriate try-catch block if necessary), I would like to invoke the iterator()
method on getMeDirStream
to do some downstream operations.
Your specific questions are difficult to address because it's unclear exactly what you're trying to achieve. In particular, when you ask what the purpose of the try
block is... Well, you wrote it, so only you can answer that.
In general, you never call get
on an Option
. You either use pattern matching:
option match {
case Some(value) => /* ... */
case None => /* ... */
}
or you use methods like map
, flatMap
, and foreach
(or the equivalent comprehension syntax that gpampara's code uses).
My revision of gpampara's answer:
import scala.collection.convert.wrapAll._
import scala.util.Try
import java.nio.file.{Paths, Files, Path}
val getMeDirStream: Option[Iterator[Path]] =
for {
path <- Try(Paths.get("")).toOption
directoryStream <- Try(Files.newDirectoryStream(path)).toOption
} yield directoryStream.iterator
Changes:
Try(...).toOption
instead of Either
scala.collection.convert
to return the result as a Scala Iterator
.Try
is similar to Option
. Instead of Some
and None
, it has Success
and Failure
subtypes, and the failure case includes a Throwable
, whereas None
is just a singleton with no additional information.