6
\$\begingroup\$

I want to get just the first line of a big string. Currently, here's how I do it:

def getFirstParagraph(txt: String) = {
    val newLineIdx = txt.indexOf("\n") match {
        case i: Int if i > 0 => i
        case _               => txt.length
    }

    txt.substring(0, newLineIdx)
}

But my friend sees some downfall: if txt is null, there will be an exception. His suggestion involved using var:

def getFirstParagraph(txt: String) = {
    var result = txt
    scala.util.control.Exception.ignoring(classOf[Exception]) {
        result = result.substring(0, result.indexOf("\n"))
    }
    result
}

Which will handle the null value fine. Thing is, I'm quite uncomfortable using var. How can I handle this case without using var (aka the Scala / functional way)?

\$\endgroup\$
10
\$\begingroup\$
scala> def getFirstParagraph(txt: String) = {
         Option(txt).map(_.takeWhile(c => c != '\n')).orNull
       }
getFirstParagraph: (txt: String)String

scala> getFirstParagraph(null)
res2: String = null

scala> getFirstParagraph("fsdfasf")
res3: String = fsdfasf

scala> getFirstParagraph("fsdfasf\nxxxxxxx")
res4: String = fsdfasf

Option(txt) converts txt into an Option[String] which will be None if txt is null.

map will execute the takeWhile only if the Option is Some.

Finally orNull will pull the value out of the Option if it is Some or evaluate to null otherwise.

\$\endgroup\$
  • \$\begingroup\$ This gives me a warning: "<console>:9: warning: comparing values of types Char and java.lang.String using `!=' will always yield true" on Sacla 2.9.2, also the code didn't work... \$\endgroup\$ – bertzzie Aug 13 '12 at 4:03
  • \$\begingroup\$ Nevermind, silly mistake. I tested against "\n", not '\n'. Sorry. \$\endgroup\$ – bertzzie Aug 13 '12 at 4:08
12
\$\begingroup\$

Here's my take on it:

def getFirstParagraph(txt: String): String = txt.lines.next

As to the null objection: in idiomatic Scala, you don't use null. If there's some API which might return you a null string, then, at that point, you turn it into an Option, and handle the Option elsewhere as needed.

Handling null (or even Option) at the getFirstParagraph method is misplaced.

\$\endgroup\$
  • \$\begingroup\$ I agree on the misplaced responsabilities note. \$\endgroup\$ – fedesilva Aug 13 '12 at 23:00
  • \$\begingroup\$ Good point, I agree. \$\endgroup\$ – sourcedelica Aug 14 '12 at 3:19
5
\$\begingroup\$

ericacm's code may be shortened (removing explicit lambda notation). Also, propagating null is a bad/dangerous thing (unless you are forced to stay close to the metal, but then how about writing in C), so why not return an Option?

def getFirstParagraph(txt: String) = {
    Option(txt).map(_.takeWhile(_ != '\n'))
}

Or, if you don't use this from Java, testing for null is kinda weird, as in pure world there is no null. So there is:

def getFirstParagraph(txt: String) = {
    txt.takeWhile(_ != '\n')
}
\$\endgroup\$
  • 1
    \$\begingroup\$ In the second case map call is excess. \$\endgroup\$ – citxx Nov 17 '12 at 15:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.