1
val myArray = Array("1", "2")
val error = myArray(5)//throws an ArrayOutOfBoundsException

myArray has no fixed size, which explains why a call like performed on the above second line might happen.

First, I never really understood the reasons to use error handling for expected errors. Am I wrong to consider this practice as bad, resulting from poor coding skills or an inclination towards laziness?

What would be the best way to handle the above case?

  • What I am leaning towards: basic implementation (condition) to prevent accessing the data like depicted;
  • use Option;
  • use Try or Either;
  • use a try-catch block.
2
  • It's not really clear what you're asking for. Do you refer to the potential of an ArrayOutOfBoundsException if you would do myArray(5) ? If so, how to handle that will depend on context. You can always check size and avoid the exception. Commented Oct 28, 2016 at 7:08
  • For any code that can throw an exception, you should wrap it in a Try. Then you can do whatever you want with that Try. Commented Oct 28, 2016 at 7:12

3 Answers 3

1

1 Avoid addressing elements through index

Scala offers a rich set of collection operations that are applied to Arrays through ArrayOps implicit conversions. This lets us use combinators like map, flatMap, take, drop, .... on arrays instead of addressing elements by index.

2 Prevent access out of range

An example I've seen often when parsing CSV-like data (in Spark):

case class Record(id:String, name: String, address:String)
val RecordSize = 3
val csvData = // some comma separated data
val records = csvData.map(line => line.split(","))
                     .collect{case arr if (arr.size == RecordSize) => 
                              Record(arr(0), arr(1), arr(2))}

3 Use checks that fit in the current context

If we are using monadic constructs to compose access to some resource, use a fitting way of lift errors to the application flow: e.g. Imagine we are retrieving user preferences from some repository and we want the first one:

Option

def getUserById(id:ID):Option[User]
def getPreferences(user:User) : Option[Array[Preferences]]

val topPreference = for {
      user <- userById(id)
      preferences <- getPreferences(user)
      topPreference <- preferences.lift(0)
   } yield topPreference

(or even better, applying advice #1):

val topPreference = for {
      user <- userById(id)
      preferences <- getPreferences(user)
      topPreference <- preferences.headOption
   } yield topPreference

Try

def getUserById(id:ID): Try[User]
def getPreferences(user:User) : Try[Array[Preferences]]
val topPreference = for {
      user <- userById(id)
      preferences <- getPreferences(user)
      topPreference <- Try(preferences(0))
   } yield topPreference

As general guidance: Use the principle of least power. If possible, use error-free combinators: = array.drop(4).take(1) If all that matters is having an element or not, use Option If we need to preserve the reason why we could not find an element, use Try.

Let the types and context of the program guide you.

Sign up to request clarification or add additional context in comments.

Comments

1

If indexing myArray can be expected to error on occasion, then it sounds like Option would be the way to go.

myArray.lift(1)  // Option[String] = Some(2)
myArray.lift(5)  // Option[String] = None

You could use Try() but why bother if you already know what the error is and you're not interested in catching or reporting it?

Comments

1

Use arr.lift (available in standard library) which returns Option instead of throwing exception.

if not use safely

Try to access the element safely to avoid accidentally throwing exceptions in middle of the code.

implicit class ArrUtils[T](arr: Array[T]) {
   import scala.util.Try
   def safely(index: Int): Option[T] = Try(arr(index)).toOption
}

Usage:

arr.safely(4)

REPL

scala> val arr = Array(1, 2, 3)
arr: Array[Int] = Array(1, 2, 3)

scala> implicit class ArrUtils[T](arr: Array[T]) {
   import scala.util.Try
   def safely(index: Int): Option[T] = Try(arr(index)).toOption
  }
defined class ArrUtils

scala> arr.safely(4)
res5: Option[Int] = None

scala> arr.safely(1)
res6: Option[Int] = Some(2)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.