Home > Software design >  Kotlin collections: 'break out' early on null / empty / blank
Kotlin collections: 'break out' early on null / empty / blank

Time:11-01

I have a list of data class items as a kind of lookup table, thereby searching for a NAME and returning the corresponding ID:

data class Test(
  var ID: String,
  var NAME: String
)

val lookupList = listOf(
  Test(ID ="0B82B4DEB07046B28BE6B861B6851DAD", NAME = "Alpha"),
  Test(ID ="1F72F6C6AAB94F94B18A3AD661A2907E", NAME = "Beta"),
  Test(ID ="4C23246F49EB40BB9D71FB9D0FBE25C0", NAME = "Gamma"),
  Test(ID ="5D5F022A29934C77AE48E7FCFB0B985F", NAME = "Delta")
)

val testName = "Gamma"

val resultID = lookupList
  .filter { it.NAME == testName }
  .map { it.ID }                             // will fail when testName = ""
  .first()

println(resultID)   // prints "4C23246F49EB40BB9D71FB9D0FBE25C0"

Now in some cases testName can be empty. In that case the application will crash on .map { it.ID } as the filtered list will be empty.

In such a case resultID should get to be assigned null. The best I can come up with is to add a Test() entry for NAME = "" to the lookup list:

data class Test(var ID: String, var NAME: String)

val lookupList = listOf(
  Test(ID ="0B82B4DEB07046B28BE6B861B6851DAD", NAME = "Alpha"),
  Test(ID ="1F72F6C6AAB94F94B18A3AD661A2907E", NAME = "Beta"),
  Test(ID ="4C23246F49EB40BB9D71FB9D0FBE25C0", NAME = "Gamma"),
  Test(ID ="5D5F022A29934C77AE48E7FCFB0B985F", NAME = "Delta")
)

val testName = ""

val resultID = lookupList
  .union(listOf(Test(ID = "", NAME = "")))   // add case for empty NAME
  .filter { it.NAME == testName }
  .map { it.ID }
  .first().ifBlank { null }                  // return null for empty NAME

println(resultID)

Is there a better solution? Is there a way to 'return early' with null from within the chain? I tried with ifEmpty() but to no avail.

One remark: testName will always be one of the NAME values in lookupList or the empty string, never a non-empty string which is not in lookupList.

CodePudding user response:

I don't think it's the call to map that's failing, but rather the call to first. Try using firstOrNull instead.

val resultID = lookupList
  .filter { it.NAME == testName }
  .map { it.ID }
  .firstOrNull()
  • Related