Et typisk problem med Javakode er bruken av null for objekt-referanser som ikke har noen verdi. Typisk vil et API returnere null i de tilfeller den etterspurte egenskapen ikke har noen verdi. For eksempel slik, ikke alle personer har noen registrert partner:
// Returns "null" if no partner Person partner = customer.getPartner(); // Potensial NullPointerException doStuff(partner.getName()); // Safe use - ugly code if(partner != null) { doStuff(partner.getName()); }
De fleste kodebaser på Java-prosjekter har mange null-sjekker, og de får gjerne fler etter at man oppdager NullPointerException på steder man ikke hadde forutsett. Dette gjør koden stygg og uoversiktlig. Og enda verre blir det hvis man har flere nøstede objekter:
if(partner != null) { Name partnerName = partner.getName(); if(partnerName != null) { String partnerFirstName = partnerName.getFirstName(); if(partnerFirstName != null) { doStuff(partnerFirstName.toUpperCase()); } } }
Hvordan kan man løse dette problemet i Scala? Jo, ved å ta i bruk Option-typen. Den har enten verdien None hvis det ikke er noen verdi, eller Some[T] hvis det er noen verdi. Selve verdien kan hentes på en rekke forskjellige måter. Det som er fint er at None også er et objekt med metoder, slik at man slipper exceptions om man ikke eksplisitt sjekker om verdien er satt.
Hvis vi selv skriver koden kan vi la verdien returnere en Option av typen i stedet for null/typen direkte:
// Returns Option[Person] instead of Person directly val partner = customer.getPartner if(!partner.isEmpty) { doStuff(partner.get.getName) }
Dette så jo ikke spesielt kult ut. Hvis vi fortsatt må sjekke om verdien er satt kan vi jo like godt sjekke for null? Men siden vi har masse funksjonelle godsaker tilgjengelig trenger vi ikke gjøre det. Metoden foreach vil bare la være å gjøre noe om verdien er None:
partner.foreach(doStuff(_.getName))
Det nøstede eksempelet løses fint med metoden map:
partner.map(_.getName).map(_.getFirstName).foreach(doStuff(_.toUpperCase))
Eller tilsvarende med for-comprehension om man synes det blir rotete med alle metodene (mindre-enn tegnet blir dessverre feil her):
for { name <- partner.getName firstName <- name.getFirstName upperCaseName <- firstName.toUpperCase } { doStuff(upperCaseName) }
Option løser altså problemet med null-sjekker. En siste liten detalj er at Some(null) er None. Det vil si at om du bruker et eksisterende Java-API som kan returnere null kan du bare pakke rundt med Some og slippe null-sjekk uansett. For eksempel om man henter parametre fra en http request, metoden getOrElse lar deg sette en default verdi hvis verdien er None:
// Typical http request in Java-servlet-api val name = Some(request.getParameter("name")).getOrElse("empty-name")
Konklusjonen er at bruken av null som default/ukjent verdi i Java utgjør et problem for de som skal benytte koden. Dersom man programmerer i Scala kan man bruke Option for å vise ta verdien ikke nødvendigvis er satt, i tillegg til at man tillater funksjonell bruk uten eksplisitt sjekking av verdien.
Må man skrive kode i Java kan det være lurt å ta i bruk en egen klasse for å representere slike verdier. For eksempel en av disse implementasjonene: