56
Scala for Java Developers © 2011 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Scala for Java Developers

Embed Size (px)

DESCRIPTION

My presentation at SpringOne. The target audience is Java developers who haven't started with Scala yet.

Citation preview

Page 1: Scala for Java Developers

Scala for Java Developers

© 2011 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Page 2: Scala for Java Developers

What is Scala

2

“a general purpose programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It smoothly integrates features of object-oriented and functional languages, enabling Java and other programmers to be more productive.”

http://www.scala-lang.org

Page 3: Scala for Java Developers

Object-oriented

• Everything is an object– No “primitives”

• Classes– Same as Java, but concise

• Traits– Interfaces done right

• Singletons– Language-level concept

3

Page 4: Scala for Java Developers

Statically typed

• Rich type system (by Java’s standard)– Higher-kinded types

– Implicit conversions

– Type evidence

• Expressive type system• Inferred types

4

Page 5: Scala for Java Developers

Functional Programming

• Functions as values– May be

• Saved• Passed to other functions (higher-order functions)

No need to write ugly anonymous classes

– Advanced pattern matching

– Expressions return a value• if/else, try/catch, match, …

• Promotes immutability– But Scala doesn’t force it

5

Page 6: Scala for Java Developers

Java Interoperability

• Compiles to Java byte code– Jars, wars, …

– No special operational change

• Scala calling Java, Java calling Scala code is fine• Whole Java eco-system at your service

• You can write apps using Scala and Spring, today

6

Page 7: Scala for Java Developers

Hello World: Scripting Style

$ scala hello-script.scalaHello World$ scala hello-script.scalaHello World

No compilationNo compilation

Page 8: Scala for Java Developers

Hello World: Porting of Java Code

$ scalac hello-java.scala$ scala example.MainHello World

$ scalac hello-java.scala$ scala example.MainHello World

‘static’‘static’

Inferred semicolons

Inferred semicolons

Page 9: Scala for Java Developers

Hello World: Using the App trait

$ scalac hello-app.scala$ scala example.MainHello World

$ scalac hello-app.scala$ scala example.MainHello World

Page 10: Scala for Java Developers

Simple Class

class Personclass Person

val p = new Person val p = new Person

Type Inferred

Type Inferred

Default access: public

Default access: public

No curly braces needed (but allowed)

No curly braces needed (but allowed)

Page 11: Scala for Java Developers

Simple Class

class Personclass Person

val p: Person = new Person val p: Person = new Person

Explicit type specificationExplicit type specification

Page 12: Scala for Java Developers

Class with constructor

class Person(firstName: String, lastName: String)class Person(firstName: String, lastName: String)

val p = new Person("Ramnivas", "Laddad") println(p.firstName) // Error val p = new Person("Ramnivas", "Laddad") println(p.firstName) // Error

Primary constructor

Primary constructor

Fields – accessible in class body

Fields – accessible in class body

Page 13: Scala for Java Developers

Class with “getters”

class Person(val firstName: String, val lastName: String)class Person(val firstName: String, val lastName: String)

val p = new Person("Ramnivas", "Laddad") println(p.firstName) val p = new Person("Ramnivas", "Laddad") println(p.firstName)

Value (Java ‘final’)

Value (Java ‘final’)

Page 14: Scala for Java Developers

Class with “getters” and “setters”

class Person(var firstName: String, var lastName: String)class Person(var firstName: String, var lastName: String)

val p = new Person("Ramnivas", "Laddad")println(p.firstName)p.firstName = "Ramnivas2”

val p = new Person("Ramnivas", "Laddad")println(p.firstName)p.firstName = "Ramnivas2”

Variable (Java non-final)

Variable (Java non-final)

Page 15: Scala for Java Developers

Extending a class

val s = new Student("Ramnivas", "Laddad", 1)println(s.firstName)println(s.grade)

val s = new Student("Ramnivas", "Laddad", 1)println(s.firstName)println(s.grade)

Page 16: Scala for Java Developers

Defining methods

class Person(val firstName: String, val lastName: String) { def name = firstName + " " + lastName

override def toString = name }

class Person(val firstName: String, val lastName: String) { def name = firstName + " " + lastName

override def toString = name }

val p = new Person("Ramnivas", "Laddad")println(p.name) // Ramnivas Laddadprintln(p) // Ramnivas Laddad

val p = new Person("Ramnivas", "Laddad")println(p.name) // Ramnivas Laddadprintln(p) // Ramnivas Laddad

Not optionalNot optional

Page 17: Scala for Java Developers

Uniform access principle

class Person(val firstName: String, val lastName: String) { val name = firstName + " " + lastName

override def toString = name }

class Person(val firstName: String, val lastName: String) { val name = firstName + " " + lastName

override def toString = name }

val p = new Person("Ramnivas", "Laddad")println(p.name) // Ramnivas Laddadprintln(p) // Ramnivas Laddad

val p = new Person("Ramnivas", "Laddad")println(p.name) // Ramnivas Laddadprintln(p) // Ramnivas Laddad

Page 18: Scala for Java Developers

Names in Scala

• Class, method, field names can contain non alpha-numeric characters– ::

– :::

– ~>

– f@#:

• Valuable if used judiciously– DSLs

18

Page 19: Scala for Java Developers

More about methods and fields

• Declaring abstract methods and fields– Just don’t provide definition

def learn(subject: String) val knowledge

• Classes with abstract method must be declared abstract– Just as in Java

• Methods can be defined inside methods• Methods may be marked @tailrec to check for tail

recursiveness

19

Page 20: Scala for Java Developers

Finer access control levels

• Default access level: public• Protected: protected

– Same as Java

• Private:– private – private[this] Access only from this instance – private[package-name] Access from package and its

subpackages

20

Page 21: Scala for Java Developers

Traits: Interfaces done right

21

trait PartyGoer { val age: Int val yearsUntilLegalDrinking = if (age >= 18) 0 else 18-age}

trait PartyGoer { val age: Int val yearsUntilLegalDrinking = if (age >= 18) 0 else 18-age}

Page 22: Scala for Java Developers

Collections

val people = List("John", "Jacob", "Mike")val people = List("John", "Jacob", "Mike")

Page 23: Scala for Java Developers

Collections

val people = Array("John", "Jacob", "Mike")val people = Array("John", "Jacob", "Mike")

Page 24: Scala for Java Developers

Working with collections: for comprehension

24

for (person <- people) { println(person)}

for (person <- people) { println(person)}

Page 25: Scala for Java Developers

Working with collections: for comprehension

25

for (person <- people if person startsWith "J") { println("""Lucky one to start name in "J" """ + person)}

// You are lucky one to start name in "J" John// You are lucky one to start name in "J" Jacob

for (person <- people if person startsWith "J") { println("""Lucky one to start name in "J" """ + person)}

// You are lucky one to start name in "J" John// You are lucky one to start name in "J" Jacob

Page 26: Scala for Java Developers

Working with collections: filter

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

Page 27: Scala for Java Developers

Working with collections: filter

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

Page 28: Scala for Java Developers

Working with collections: using _

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

Page 29: Scala for Java Developers

Working with collections: passing method as function

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

Page 30: Scala for Java Developers

Working with collections: partition

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val (elementarySchoolers, middleSchoolers) = students.partition(_.grade < 6)println(elementarySchoolers)println(middleSchoolers)//List(first1 last1, first2 last2, first3 last3)//List(first4 last4)

val (elementarySchoolers, middleSchoolers) = students.partition(_.grade < 6)println(elementarySchoolers)println(middleSchoolers)//List(first1 last1, first2 last2, first3 last3)//List(first4 last4)

TupleTuple

Page 31: Scala for Java Developers

Working with collections: transforming

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

val student1 = new Student("first1", "last1", 1)val student2 = new Student("first2", "last2", 1)val student3 = new Student("first3", "last3", 2)val student4 = new Student("first4", "last4", 6)val students = List(student1, student2, student3, student4)

Page 32: Scala for Java Developers

Map

println(studentSchools(student1)) // Millerprintln(studentSchools(student1)) // Miller

Page 33: Scala for Java Developers

More collections

• Set• IndexedSeq• Vector (good one!)• Range

– 1 to 100 – 1 until 100– 2 until 100 by 2

• …

• Mutable versions• Parallel versions

33

Page 34: Scala for Java Developers

Putting it together: Quicksort

def quicksort[T](input: Traversable[T]) (ordering: Ordering[T]) : Traversable[T] = if (input.isEmpty) { input } else { val (low, high) = input.tail.partition(ordering.lt(_, input.head)) quicksort(low)(ordering) ++ List(input.head) ++ quicksort(high)(ordering) }

def quicksort[T](input: Traversable[T]) (ordering: Ordering[T]) : Traversable[T] = if (input.isEmpty) { input } else { val (low, high) = input.tail.partition(ordering.lt(_, input.head)) quicksort(low)(ordering) ++ List(input.head) ++ quicksort(high)(ordering) }

println(quicksort(List(1, 3, 4, 5, 1))(Ordering.Int))println(quicksort(List(1, 3, 4, 5, 1))(Ordering.Int))

Page 35: Scala for Java Developers

Putting it together: Quicksort

println(quicksort(List(1, 3, 4, 5, 1)))println(quicksort(List(1, 3, 4, 5, 1)))

Page 36: Scala for Java Developers

Pattern matching: Basics

val a:Any = "foo" a match { case str: String => println("A string: " + str) case i: Int => println("An int: " + i) case _ => println("Something else")}

val a:Any = "foo" a match { case str: String => println("A string: " + str) case i: Int => println("An int: " + i) case _ => println("Something else")}

Page 37: Scala for Java Developers

Pattern matching: with collections

val l = List("a", "b", "c") l match { case Nil => println("Empty!") case head :: Nil => println("Only one item " + head) case head :: tail => println("Item " + head + " followed by " + tail) }

val l = List("a", "b", "c") l match { case Nil => println("Empty!") case head :: Nil => println("Only one item " + head) case head :: tail => println("Item " + head + " followed by " + tail) }

Page 38: Scala for Java Developers

Quicksort with pattern matching

def quicksort[T](input: Traversable[T]) (implicit ordering: Ordering[T]) : Traversable[T] = input match { case head :: tail => val (low, high) = tail.partition(ordering.lt(_, head)) quicksort(low) ++ List(head) ++ quicksort(high) case _ => input }

def quicksort[T](input: Traversable[T]) (implicit ordering: Ordering[T]) : Traversable[T] = input match { case head :: tail => val (low, high) = tail.partition(ordering.lt(_, head)) quicksort(low) ++ List(head) ++ quicksort(high) case _ => input }

println(quicksort(List(1, 3, 4, 5, 1)))println(quicksort(List(1, 3, 4, 5, 1)))

Page 39: Scala for Java Developers

Destutter using Pattern matching

39

def destutter[A](lst: List[A]): List[A] = lst match { case h1 :: h2 :: tail if (h1 == h2) => destutter(h2 :: tail) case h1 :: h2 :: tail => h1 :: destutter(h2 :: tail) case _ => lst}

def destutter[A](lst: List[A]): List[A] = lst match { case h1 :: h2 :: tail if (h1 == h2) => destutter(h2 :: tail) case h1 :: h2 :: tail => h1 :: destutter(h2 :: tail) case _ => lst}

// destutter(List(1,1,1,1,1,1)) => List(1)// destutter(List(1,1,4,3,3,2)) => List(1,4,3,2)// destutter(List() )=> List()

// destutter(List(1,1,1,1,1,1)) => List(1)// destutter(List(1,1,4,3,3,2)) => List(1,4,3,2)// destutter(List() )=> List()

Page 40: Scala for Java Developers

Case classes

• Useful in pattern matching– “case”

• Offer many useful common methods– equals()

– hashCode()

– toString

– copy()

40

Page 41: Scala for Java Developers

Case classes

41

case class Human(name: String)case class SuperHero(name: String, power: String)case class Human(name: String)case class SuperHero(name: String, power: String)

val characters = List(Human("Programmer"), SuperHero("Customer", "money"), SuperHero("QA", "testing"))

val characters = List(Human("Programmer"), SuperHero("Customer", "money"), SuperHero("QA", "testing"))

Page 42: Scala for Java Developers

Case classes and pattern matching

42

val actions = for (character <- characters) yield character match { case Human(name) => name + " needs to be saved" case SuperHero(name, power) => name + " will save using " + power }

actions.foreach(println)

val actions = for (character <- characters) yield character match { case Human(name) => name + " needs to be saved" case SuperHero(name, power) => name + " will save using " + power }

actions.foreach(println)

Page 43: Scala for Java Developers

Pattern matching and extracting just enough

43

val actions = for (character <- characters) yield character match { case Human(name) => name + " needs to be saved" case SuperHero(_, power) => "Could be saved using " + power }

actions.foreach(println)

// Programmer needs to be saved// Could be saved using money// Could be saved using testing

val actions = for (character <- characters) yield character match { case Human(name) => name + " needs to be saved" case SuperHero(_, power) => "Could be saved using " + power }

actions.foreach(println)

// Programmer needs to be saved// Could be saved using money// Could be saved using testing

Page 44: Scala for Java Developers

Regular expressions

44

val text = "Ramnivas Laddad"

val Name = """(\w+)\s+(\w+)""".r

val person = text match { case Name(first, last) => Some(new Person(first, last)) case _ => None}

println(person) // Some(Ramnivas Laddad)

val text = "Ramnivas Laddad"

val Name = """(\w+)\s+(\w+)""".r

val person = text match { case Name(first, last) => Some(new Person(first, last)) case _ => None}

println(person) // Some(Ramnivas Laddad)

Page 45: Scala for Java Developers

Options

45

val texts = List("Ramnivas Laddad", "foo", "Scott Andrews")

val peopleOptions = texts.map { _ match { case Name(first, last) => Some(new Person(first, last)) case _ => None }}

println(peopleOptions)// List(Some(Ramnivas Laddad), None, Some(Scott Andrews))

val texts = List("Ramnivas Laddad", "foo", "Scott Andrews")

val peopleOptions = texts.map { _ match { case Name(first, last) => Some(new Person(first, last)) case _ => None }}

println(peopleOptions)// List(Some(Ramnivas Laddad), None, Some(Scott Andrews))

Page 46: Scala for Java Developers

Options: flattening

46

val texts = List("Ramnivas Laddad", "foo", "Scott Andrews")

val peopleOptions = texts.map { _ match { case Name(first, last) => Some(new Person(first, last)) case _ => None }}

println(peopleOptions.flatten)// List(Ramnivas Laddad, Scott Andrews)

val texts = List("Ramnivas Laddad", "foo", "Scott Andrews")

val peopleOptions = texts.map { _ match { case Name(first, last) => Some(new Person(first, last)) case _ => None }}

println(peopleOptions.flatten)// List(Ramnivas Laddad, Scott Andrews)

Page 47: Scala for Java Developers

Options: flatMap

47

val texts = List("Ramnivas Laddad", "foo", "Scott Andrews")

val people = texts.flatMap { _ match { case Name(first, last) => Some(new Person(first, last)) case _ => None }}

println(people)// List(Ramnivas Laddad, Scott Andrews)

val texts = List("Ramnivas Laddad", "foo", "Scott Andrews")

val people = texts.flatMap { _ match { case Name(first, last) => Some(new Person(first, last)) case _ => None }}

println(people)// List(Ramnivas Laddad, Scott Andrews)

Page 48: Scala for Java Developers

Higher order functions

def process() : Unit = { retry(5) { ... }}

def process() : Unit = { retry(5) { ... }}

def retry[T](maxRetry: Int)(thunk: => T) = { def retry(thunk: => T, attempt: Int): T = { try { thunk } catch { case ex if (attempt < maxRetry) => retry(thunk, attempt + 1) } } retry(thunk, 0)}

def retry[T](maxRetry: Int)(thunk: => T) = { def retry(thunk: => T, attempt: Int): T = { try { thunk } catch { case ex if (attempt < maxRetry) => retry(thunk, attempt + 1) } } retry(thunk, 0)}

ThunkThunk

Page 49: Scala for Java Developers

Caching using Scala

def getQuoteGraph(stock: Stock, days: Int) : Array[Byte] = { cached("chart", stock.ticker + ":" + days) {

... Expensive calculation

}}

Page 50: Scala for Java Developers

Caching higher-order function

abstract class Caching(val cacheManager: CacheManager) { def cached[T](region: String, key: Any) (thunk: => T): T = { val cache = ...

if (cache.containsKey(key)) { cache.get(key).asInstanceOf[T] } else { val thunkVal: T = thunk cache.put(key, thunkVal) thunkVal } }}

Page 51: Scala for Java Developers

Transaction management

def findOrder(orderId: Long) : Order = { transactional(readOnly=true) { //... }} def updateOrder(order: Order) { transactional() { //... }}

51

Page 52: Scala for Java Developers

Transaction management function

def transactional[T](propgation: Propagation = Propagation.REQUIRED, isolation: Isolation = Isolation.DEFAULT, readOnly: Boolean = false, timeout: Int =TransactionDefinition.TIMEOUT_DEFAULT, rollbackFor: List[Throwable] = List(), noRollbackFor: List[Throwable] = List()) (thunk: => T) : T

Page 53: Scala for Java Developers

Transaction management implementation

abstract class TransactionManagement(val txManager: PlatformTransactionManager) {

def transactional[T](...)(thunk: => T) : T = { val txAttribute = new TransactionAttributeWithRollbackRules(...)

val status = txManager.getTransaction(txAttribute)

try { val ret = thunk txManager.commit(status) ret } catch { case ex => { if (txAttribute.rollbackOn(ex)) { txManager.rollback(status) } else { txManager.commit(status) } throw ex } } }}

Page 54: Scala for Java Developers

There is more… a lot more

• Methods/functions– Default parameters– Named parameters– Curried parameters– Partial functions

• Type system– Higher-kinded types– Bounded types– Implicit type conversion– Type parameter evidence– Type aliasing

• Lazy values• Partial imports• Actors• Extractors• Scala ecosystem• Combinator/parser• Continuations• Compiler plugin• …

54

Page 55: Scala for Java Developers

Learning Scala

• Read a Scala book– Get the whole picture

• May feel complex at first– Java-style Scala may serve best during initial exploration

– Over time you will appreciate its simplicity

• Learn Haskell first!– Might help to break from the Java way of thinking

55

Be ready to be humbled

Page 56: Scala for Java Developers

Scala for Java Developers

© 2011 SpringOne 2GX. All rights reserved. Do not distribute without permission.