Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the following Java "continue" code translate to Scala?

Tags:

scala

for (String stock : allStocks) {

    Quote quote = getQuote(...);
    if (null == quoteLast) {
        continue;
    }

    Price price = quote.getPrice();
    if (null == price) {
        continue;
    }

}

I don't necessarily need a line by line translation, but I'm looking for the "Scala way" to handle this type of problem.

like image 957
deltanovember Avatar asked Jul 17 '11 02:07

deltanovember


4 Answers

You don't need continue or breakable or anything like that in cases like this: Options and for comprehensions do the trick very nicely,

val stocksWithPrices =
  for {
    stock <- allStocks
    quote <- Option(getQuote(...))
    price <- Option(quote.getPrice())
  } yield (stock, quote, price);
like image 181
Miles Sabin Avatar answered Oct 27 '22 17:10

Miles Sabin


Generally you try to avoid those situations to begin with by filtering before you even start:

val goodStocks = allStocks.view.
  map(stock => (stock, stock.getQuote)).filter(_._2 != null).
  map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null)

(this example showing how you'd carry along partial results if you need them). I've used a view so that results will be computed as-needed, instead of creating a bunch of new collections at each step.

Actually, you'd probably have the quotes and such return options--look around on StackOverflow for examples of how to use those instead of null return values.

But, anyway, if that sort of thing doesn't work so well (e.g. because you are generating too many intermediate results that you need to keep, or you are relying on updating mutable variables and you want to keep the evaluation pattern simple so you know what's happening when) and you can't conceive of the problem in a different, possibly more robust way, then you can

import scala.util.control.Breaks._
for (stock <- allStocks) {
  breakable {
    val quote = getQuote(...)
    if (quoteLast eq null) break;
    ...
  }
}

The breakable construct specifies where breaks should take you to. If you put breakable outside a for loop, it works like a standard Java-style break. If you put it inside, it acts like continue.

Of course, if you have a very small number of conditions, you don't need the continue at all; just use the else of the if-statement.

like image 10
Rex Kerr Avatar answered Oct 27 '22 16:10

Rex Kerr


Your control structure here can be mapped very idiomatically into the following for loop, and your code demonstrates the kind of filtering that Scala's for loop was designed for.

for {stock <- allStocks.view
     quote = getQuote(...)
     if quoteLast != null
     price = quote.getPrice
     if null != price
    }{
      // whatever comes after all of the null tests
    }

By the way, Scala will automatically desugar this into the code from Rex Kerr's solution

val goodStocks = allStocks.view.
  map(stock => (stock, stock.getQuote)).filter(_._2 != null).
  map { case (stock, quote) => (stock,quote, quote.getPrice) }.filter(_._3 != null)

This solution probably doesn't work in general for all different kinds of more complex flows that might use continue, but it does address a lot of common ones.

like image 7
Ken Bloom Avatar answered Oct 27 '22 16:10

Ken Bloom


If the focus is really on the continue and not on the null handling, just define an inner method (the null handling part is a different idiom in scala):

def handleStock(stock: String): Unit {
  val quote = getQuote(...)
  if (null == quoteLast) {
    return
  }

  val price = quote.getPrice();
  if (null == price) {
    return
  }
}

for (stock <- allStocks) {
  handleStock(stock)
}
like image 4
Debilski Avatar answered Oct 27 '22 16:10

Debilski