scala for java programmers
Post on 10-May-2015
804 Views
Preview:
DESCRIPTION
TRANSCRIPT
Intro to Scala for Java Devs
Sungard– 4/17/2012
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
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.
What is Scala?
• Hybrid Object-Functional language • Statically typed • Developed by Martin Odersky
– Java Generics – Java Compiler (1.3+)
• First release in 2003
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
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…
Conciseness
• Code size reduced by 2-3x compared to Java
• Less code == easier to read • Less code == fewer bugs
Conciseness
• Type Inference • Expressions, not statements • Higher-ordered functions • Case classes • Pattern matching
Type Inference
• Variables
• Method return types
• Generic type parameters
val subscrip7onEvents = foo()
def listOfPeople = List(“Paul”, “Eric”, “John”, “Mar7n”)
case class MyPair[A, B](x: A, y: B) val p = MyPair(1, “foo”) // p is MyPair[Int, String]
Type inference
• Java
• Scala
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");
val customers = HashMap( "id1"-‐>Customer("Eric", "917-‐434-‐1852"), "id2"-‐>Customer("Paul", "718-‐666-‐9876"))
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
Expressions, not statements
val n = try { userInput.toInt } catch { case _ => 0 } // n is an Int, 0 if unable to parse userInput
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
Collection Literals
• val l1 = List(1, 2, 3)
• val m1 = Map(“name” -‐> “Eric”, “city” -‐> “NYC”)
• val s1 = Set(Car(“Ford”), Car(“Isuzu”), Car(“VW”))
Collections API
• Scala
• Java
val groups = subscrip7onEvents.groupBy(e => e.subscrip7on.id)
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); }
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)
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
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>
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
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
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)
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 }
Case Classes
• Case classes can also have mutable fields and methods
• In Scala you can define multiple classes per source file
case class Car(make: String, model: String, mpg: Int, var odometer) { def driveMiles(miles: Int) { odometer += miles } }
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 }
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” }
Pattern Matching
• Typed patterns
def generalSize(x: Any) = x match { case s: String => s.length case m: Map[_, _] => m.size case _ => -‐1 }
No Checked Exceptions
// Look ma, no throws clause! def foo() { throw new java.lang.Excep7on }
Concurrency-readiness
• The future present is many cores • Writing thread-safe code in Java is very
difficult – Mostly due to shared, mutable state
Concurrency-readiness
• Scala – Excellent support for immutability – Actors / Futures – Parallel collections
Immutability
• Case classes • Immutable collections are default
– Copies of collections share data
• val vs. var, val is encouraged • Method parameters are vals
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
Actors
object Coun7ngActor extends Actor { def act() { for (i <-‐ 1 to 10) { println("Number: "+i) Thread.sleep(1000) } } } Coun7ngActor.start()
Actors
import scala.actors.Actor._ val echoActor = actor { while (true) { receive { case msg => println("received: ” + msg) } } } echoActor ! "hello" echoActor ! "world!"
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
Actors / Futures / STM
• Akka provides more robust Actors and Futures
• Also provides – Distributed (Remote) Actors – Software Transactional Memory – Java API
Parallel Collections
• Add .par to collection to get parallel version
• Uses JDK7 fork-join framework • Example:
– Filter is run in parallel, results are collected, then map is run in parallel
myData.par.filter(_.expensiveTest()).map(_.expensiveComputa7on())
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
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 } }
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” }
JavaConversions
• Add Scala collection API methods to Java collections
import collec7on.JavaConversions._ import collec7on.Iterable import java.u7l.{List=>JList} def goodStudents(students: JList[Student]): Iterable[String] = students.filter(_.score > 5).map(_.name)
Named and Default Params
• Named parameters
• Default parameters
def resize(width: Int, height: Int) = { ... } resize(width = 120, height = 42)
def f(elems: List[Int], x: Int = 0, cond: Boolean = true) f(List(1)) f(Nil, cond = false)
By-name Parameters
• Method parameters can be lazily evaluated
class Logger { def debug(msg: => String) {
if (isDebug) doLog(DEBUG, msg) } } log.debug(“this “ + “ is “ + “expensive”)
Type Conveniences
• Type Aliases type MyMap = mutable.HashMap[String, mutable.HashMap[String, Int]]
• Import Aliases import com.nyx.domain.no7fica7on.{Topic=>DomainTopic}
Mixins
• Multiple implementation inheritance trait UserIden7fierCmd extends ApiKeyCmd { var userId: String = _ def getUser = {…} } trait RoleIdCmd extends ApiKeyCmd { var… def… } object cmd extends UserIden7fierCmd with RoleIdCmd {..}
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) {} }
More Information
• My Scala Links gist – https://gist.github.com/1249298
top related