This document provides an introduction to Scala for Java developers. It discusses that Scala is a hybrid object-oriented and functional language that runs on the JVM and interoperates well with Java. It highlights several features of Scala that allow for more concise code compared to Java, such as type inference, expressions instead of statements, higher-order functions, and case classes.
2. Intro
• Eric Pederson
– eric@cpextechnology.com
– Twitter @ericacm
– Sourcedelica.com/blog
– Background in Java, Groovy, Javascript, PHP, etc.
• Using Scala for last two years
• Two Scala apps developed for NYSE in
Production
3. Platform at NYSE
• Scala 2.9.1
• JDK 1.6
• Tomcat / JBoss
• Maven
• Using lots of Java libraries
– Spring, Hibernate, CXF, Mule, ApacheMQ
– Bouncycastle, OpenSAML, Velocity, etc, etc.
4. What is Scala?
• Hybrid Object-Functional language
• Statically typed
• Developed by Martin Odersky
– Java Generics
– Java Compiler (1.3+)
• First release in 2003
5. What is Scala?
• Designed for general purpose
programming
• Performance on par with Java*
• Scalable
– Designed to write programs ranging from
scripts up to huge systems
– You don’t have to use all of the features to be
productive
*
There
are
some
gotchas
you
have
to
watch
out
for
6. Why Should I Use Scala?
• Allows you to write very concise code
– Productivity on the level of Groovy / Ruby
• Concurrency-ready
• Excellent interoperability with Java code
• Lots of other reasons…
7. Conciseness
• Code size reduced by 2-3x compared to
Java
• Less code == easier to read
• Less code == fewer bugs
8. Conciseness
• Type Inference
• Expressions, not statements
• Higher-ordered functions
• Case classes
• Pattern matching
9. Type Inference
• Variables
val
subscrip7onEvents
=
foo()
• Method return types
def
listOfPeople
=
List(“Paul”,
“Eric”,
“John”,
“Mar7n”)
• Generic type parameters
case
class
MyPair[A,
B](x:
A,
y:
B)
val
p
=
MyPair(1,
“foo”)
//
p
is
MyPair[Int,
String]
10. Type inference
• Java
HashMap<String,
Customer>
customers
=
new
HashMap<String,
Customer>();
customers.add("id1",
new
Customer("Eric",
"917-‐444-‐1234");
customers.add("id2",
new
Customer("Paul",
"718-‐666-‐9876");
• Scala
val
customers
=
HashMap(
"id1"-‐>Customer("Eric",
"917-‐434-‐1852"),
"id2"-‐>Customer("Paul",
"718-‐666-‐9876"))
11. Expressions, not statements
val
server
=
if
(environment
==
"development”)
{
val
factory
=
new
MBeanServerFactoryBean
factory.aberProper7esSet()
factory.getObject.asInstanceOf[MbeanServer]
}
else
{
val
clazz
=
Class.forName("org.jboss.mx.u7l.MBeanServerLocator")
clazz.getMethod("locateJBoss”).invoke(null)
}
//
server is assigned one of the bold values
12. Expressions, not statements
val
n
=
try
{
userInput.toInt
}
catch
{
case
_
=>
0
}
//
n
is
an
Int,
0
if
unable
to
parse
userInput
13. Collections API
• Very comprehensive
– For example, over 200 methods on List
• Higher ordered functions
– foreach,
map,
flatMap,
exists,
forall,
find,
findAll,
filter,
groupBy,
par77on, etc.
• Concise literals
• Immutable and mutable variations
14. Collection Literals
• val
l1
=
List(1,
2,
3)
• val
m1
=
Map(“name”
-‐>
“Eric”,
“city”
-‐>
“NYC”)
• val
s1
=
Set(Car(“Ford”),
Car(“Isuzu”),
Car(“VW”))
15. Collections API
• Scala
val
groups
=
subscrip7onEvents.groupBy(e
=>
e.subscrip7on.id)
• Java
Map<String,
List<SubscripLonEvent>>
groups
=
new
HashMap<String,
ArrayList<Subscrip7onEvent>();
for
(Subscrip7onEvent
se
:
subscrip7onEvents)
{
ArrayList<Subscrip7onEvent>
seList
=
groups.get(se.subscrip7on.id)
if
(seList
==
null)
{
seList
=
new
ArrayList<Subscrip7onEvent>();
groups.put(se.subscrip7on.id,
seList)
}
seList.add(se);
}
16. Count characters in documents
Try #1 – Java-esque Scala
var
total
=
0
for
(doc
<-‐
docs)
{
total
+=
doc.length
}
Try #2 – Use higher order functions
var
total
=
0
docs.foreach(doc
=>
total
+=
doc.length)
17. Count characters in documents
Try #3 – Use fold
docs.foldLeb(0)((accum,
current)
=>
accum
+
current.length)
Try #4 – Use type-classes (eg. Numeric)
docs.map(_.length).sum
Try #5 – Use the 'view' method to turn multiple
passes into one
docs.view.map(_.length).sum
18. Variables
scala>
var
i
=
0
i:
Int
=
0
scala>
i
=
2
i:
Int
=
2
scala>
val
j
=
0
j:
Int
=
0
scala>
j
=
3
<console>:8:
error:
reassignment
to
val
scala>
lazy
val
l
=
expensiveComputa7on()
l:
Double
=
<lazy>
19. Uniform Access Principle
scala>
object
Ints
{
|
var
i
=
1
|
val
j
=
2
|
def
k
=
i
+
j
|
}
scala>
Ints.i
res8:
Int
=
1
scala>
Ints.j
res9:
Int
=
2
scala>
Ints.k
res10:
Int
=
3
20. Uniform Access Principle
scala>
object
M
{
|
private
var
pm
=
0
|
def
m
=
pm
|
def
m_=(in:
Int)
{
pm
=
in
}
|
}
scala>
import
M._
scala>
m
res5:
Int
=
0
scala>
m
=
5
m:
Int
=
5
21. Case Classes
• Scala
scala>
case
class
Car(make:
String,
model:
String,
mpg:
Int)
defined
class
Car
scala>
val
c
=
Car("Honda",
"Civic",
40)
c:
Car
=
Car(Honda,Civic,40)
22. Case Classes
• Java
public
class
Car
implements
scala.Product,
scala.Serializable
{
final
private
String
make,
model;
final
private
int
mpg;
Car(String
make,
String
model,
int
mpg)
{
this.make
=
make;
this.model
=
model;
this.mpg
=
mpg;
}
public
String
getMake()
{
return
make;
}
public
String
getModel()
{
return
model;
}
public
int
getMpg()
{
return
mpg;
}
public
String
toString()
{
return
“Car(
“
+
make
+
….
}
public
boolean
equals(Object
that)
{
if
(that
instanceOf
Car)
&&
……
}
public
int
hashCode()
{
return
19
+
……
}
public
Car
copy(String
make,
String
model,
int
mpg)
{
…..
}
//
plus
9
other
Scala-‐specific
methods
}
23. Case Classes
• Case classes can also have mutable fields
and methods
case
class
Car(make:
String,
model:
String,
mpg:
Int,
var
odometer)
{
def
driveMiles(miles:
Int)
{
odometer
+=
miles
}
}
• In Scala you can define multiple classes
per source file
24. Pattern Matching
• Case Classes
// Class hierarchy:
trait Expr
case class Num(value : int) extends Expr
case class Var(name : String) extends Expr
case class Mul(left : Expr, right : Expr) extends Expr
// Simplification rule:
e match {
case Mul(x, Num(1)) ⇒ x
case _ ⇒ e
}
25. Pattern Matching
• Match on constants
def
describe(x:
Any)
=
x
match
{
case
5
=>
"five"
case
true
=>
"truth"
case
"hello"
=>
"hi!”
case
Nil
=>
"the
empty
list"
case
_
=>
"something
else”
}
26. Pattern Matching
• Typed patterns
def
generalSize(x:
Any)
=
x
match
{
case
s:
String
=>
s.length
case
m:
Map[_,
_]
=>
m.size
case
_
=>
-‐1
}
28. Concurrency-readiness
• The future present is many cores
• Writing thread-safe code in Java is very
difficult
– Mostly due to shared,
mutable state
30. Immutability
• Case classes
• Immutable collections are default
– Copies of collections share data
• val vs. var, val is encouraged
• Method parameters are vals
31. Actors
• Included in standard Scala library
• Simplified multithreading and
coordination
• Based on message passing
– Each actor has a mailbox queue of messages
• Implementation based on Erlang
32. Actors
object
Coun7ngActor
extends
Actor
{
def
act()
{
for
(i
<-‐
1
to
10)
{
println("Number:
"+i)
Thread.sleep(1000)
}
}
}
Coun7ngActor.start()
33. Actors
import
scala.actors.Actor._
val
echoActor
=
actor
{
while
(true)
{
receive
{
case
msg
=>
println("received:
”
+
msg)
}
}
}
echoActor
!
"hello"
echoActor
!
"world!"
34. Futures
Return a Future immediately, run func in new thread
scala>
future
{
Thread.sleep(10000);
println("hi");
10
}
res2:
scala.actors.Future[Int]
=
<
func7on0>
Use the Future apply()
method to get the result
scala>
res2()
//
blocks
wai7ng
for
sleep()
to
finish
hi
res3:
Int
=
10
35. Actors / Futures / STM
• Akka provides more robust Actors and
Futures
• Also provides
– Distributed (Remote) Actors
– Software Transactional Memory
– Java API
36. Parallel Collections
• Add .par to collection to get parallel
version
• Uses JDK7 fork-join framework
• Example:
myData.par.filter(_.expensiveTest()).map(_.expensiveComputa7on())
– Filter is run in parallel, results are collected,
then map is run in parallel
37. Interoperability with Java
• Scala classes are Java classes
• You can pass Scala objects to Java
methods and vice-versa
• For the most part, seamless interop
– Cannot use Scala-only features from Java
38. Java Interop Example
@En7ty
class
Subscrip7onEvent
{
@Id
@GeneratedValue
var
id:
Long
=
_
@ManyToOne(op7onal=false)
var
subscrip7on:
Subscrip7on
=
_
var
address:
String
=
_
@Index(name="Subscrip7onEventStatus")
private
var
status:
String
=
_
def
deliveryStatus
=
DeliveryStatus.withName(status)
def
deliveryStatus_=(s:
DeliveryStatus)
{
status
=
s.toString
}
}
39. Java Interop Example
@Controller
@RequestMapping(Array("/report"))
class
ReportController
{
class
MessageDto(message:
Message)
{
@BeanProperty
val
id
=
message.id
@BeanProperty
val
address
=
message.address
//
…
}
@RequestMapping(Array("/messages"))
def
messages(@RequestParam(value="fromDate”)
from:
String,
map:
ExtendedModelMap):
String
=
{
//…
map.put(“messages”,
asJavaCollec7on(messageDtos))
“report/messages”
}
45. Duck Typing
type
Closeable
=
{
def
close():
Unit
}
def
using[T
<:
Closeable,
S]
(obj:
T)(func:
T
=>
S):
S
=
{
val
result
=
func
(obj)
obj.close()
result
}
val
fis
=
new
FileInputStream(“data.txt”)
using(fis)
{
f
=>
while
(f.read()
!=
-‐1)
{}
}