A Scala tutorial for Java developers

Image for post
Image for post

Introduction

Image for post
Image for post

Scala pros: what makes it great

Concise syntax

class UserInfo {
private String name;
private LocalDate birthDate;

public UserInfo(String name, LocalDate birthDate) {
this.name = name;
this.birthDate = birthDate;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public LocalDate getBirthDate() {
return birthDate;
}
}
class UserInfo(var name: String, val birthDate: LocalDate)

Case Classes

LocalDate date = LocalDate.now();
UserInfo a = new UserInfo("John", date);
UserInfo b = new UserInfo("John", date);
return (a == b);
case class UserInfo(var name: String, birthDate: LocalDate)val date = LocalDate.now()
val a = new UserInfo("John", date)
val b = new UserInfo("John", date)
a == b // returns True

Pattern matching

def matchTest(x: Int): String = x match {
case 1 => "one"
case 2 => "two"
case _ => "many"
}
def matchOnType(x: Any): String = x match {
case x: Int => s"$x is integer"
case x: String => s"$x is string"
case _ => "unknown type"
}
matchOnType(1) // returns 1 is integer
matchOnType("1") // returns 1 is string
def matchList(x: List[Int]): String = x match {
case List(_) => "a single element list"
case List(_, _) => "a two elements list"
case List(1, _*) => "a list starting with 1"
}
matchList(List(3)) // returns a single elements list matchList(List(0, 1)) // returns a two elements list
matchList(List(1, 0, 0)) // returns a list starting with 1
case class UserInfo(var name: String, birthDate: LocalDate)def isUserJohn(x: Any): Boolean = x match {
case UserInfo("John", _) => true
case
_ => false
}
val list = List(
"wrong user type",
UserInfo("Ben", LocalDate.now()),
UserInfo("John", LocalDate.now()))
list.filter(isUserJohn) // list with one element UserInfo John

Implicit Classes

object Extensions {
implicit class UserInfoExt(user: UserInfo) {
def getAge(): Int = {
Years.yearsBetween(LocalDate.now(), user.birthDate,).getYears
}
}
}
import Extensions._
val user = new UserInfo("John", LocalDate.now())
user.getAge()

Higher-order functions

def multiply(x: Int): Int = x * 2

List(1, 2, 3).map(multiply) // returns 2 4 6
def isEven(x: Int): Boolean = x % 2 == 0
List(1, 2, 3).filter(isEven) // returns 2
def apply(f: Int => String, x: Int): String = f(x)
def printInt(x: Int): String = s"Printing integer $x"
apply(printInt, 3)

Option Monad

class Document {
def getActivePage: Page = ???
}
class Page {
def getSelectedText: String = ???
}
def getSelectedTextLength(doc: Document): Int = {
if(doc != null) {
val page = doc.getActivePage
if(page != null){
val text = page.getSelectedText
if(text != null){
text.length
}
else 0
}
else 0
}
else 0
}
def getSelectedTextLength(doc: Document): Int = {
if(doc == null)
return 0

val page = doc.getActivePage
if(page == null)
return 0

val text = page.getSelectedText
if(text == null)
return 0

text.length
}
def getSelectedTextLength(doc: Document): Int = {
try {
doc.getActivePage.getSelectedText.length
}
catch {
case _: NullPointerException => 0
case e: Exception => throw e
}
}
trait Option[A] {
def flatMap[B](f: A => Option[B]): Option[B]
}

case class None[A]() extends Option[A] {
def flatMap[B](f: A => Option[B]): Option[B] = new None
}

case class Some[A](a: A) extends Option[A] {
def flatMap[B](f: A => Option[B]): Option[B] = {
f(a)
}
}
class Document {
def getActivePage: Option[Page] = ???
}
class Page {
def getSelectedText: Option[String] = ???
}

def getSelectedTextLength(doc: Option[Document]): Int = {
doc
.flatMap(_.getActivePage)
.flatMap(_.getSelectedText)
.map(_.length).getOrElse(0)
}

Summary

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store