Scala For Java Programmers

5,419 views

Published on

This presentation is based on Joakim\’s experiences from moving from Java to Scala http://www.scala-lang.org/node/960#Joak We will explore how to move from Java to Scala and why. We\’ll look at things that you will run into sooner rather than later such as Scala\’s collection APIs, Options and higher order functions and special syntax. You will leave this presentation with good foundation to use Scala in practice; perhaps even in your current Java project and ideally with an appetite to learn more.

Published in: Technology
0 Comments
29 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,419
On SlideShare
0
From Embeds
0
Number of Embeds
2,469
Actions
Shares
0
Downloads
0
Comments
0
Likes
29
Embeds 0
No embeds

No notes for slide
  • Scala For Java Programmers

    1. 1. SCALA FOR JAVA PROGRAMMERS
    2. 2. AGENDA 1. Object orientation (OO) 2. Functional programming (FP) 1.1 Every value is an object 2.1 Every function is a value 1.2 Mixin-based composition with traits 2.2 Anonymous functions 1.3 Self-type annotations 2.3 Higher-order functions 1.4 Structural typing 2.4 Closures 1.5 Local type inference 2.5 Currying 1.6 Static type system 2.6 Immutability 1.7 Generic classes 2.7 For comprehensions 1.8 Variance annotations 2.8 Algebraic data types 1.9 Upper and lower type bounds 2.9 Pattern matching 1.10 Inner classes and abstract types as object members 3. Practice 1.12 Compound types 1.13 Explicitly typed self references 3.1 Square roots using Newtons method 1.14 Views, and polymorphic methods. 3.2 Finding fixed points
    3. 3. WHAT WE (REALLY) WANT YOU TO LEARN: •A Java to Scala conversion is easy • Scala brings a lot of new possibilities • You don’t have to understand all new possibilities to start with
    4. 4. JAVA ➟ SCALA LET’S START WITH A WARM-UP
    5. 5. OUR ALL JAVA MAIN Defined in Java public static void main(String[] args) { JobFactory factory = new JdbcJobFactory(); JobControl control = new JobControl(factory); ... }
    6. 6. PROJECT LAYOUT Java Application Module
    7. 7. PROJECT LAYOUT Java Java Application Module
    8. 8. PROJECT LAYOUT Java Scala Java Application Module Module
    9. 9. PROJECT LAYOUT Job.java Java Scala Java Application Module Module
    10. 10. PROJECT LAYOUT Job.scala Java Scala Java Application Module Module
    11. 11. public class Job { private String name; private List<Step> steps; private Map<String, Object> args; public Map<String, Object> getArgs() { return args; } public void setArgs(Map<String, Object> args) { this.args = args; } public List<Step> getSteps() { return steps; } public void setSteps(List<Step> steps) { this.steps = steps; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
    12. 12. public class Job { private String name; Make it compile private List<Step> steps; private Map<String, Object> args; •Public is default public Map<String, Object> getArgs() { •Variables are return args; declared with var } public void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } public List<Step> getSteps() { return steps; •Functions declared } public void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} public String getName() { return name; •void ≈ Unit } •initialize var public void setName(String name) { this.name = name; } }
    13. 13. class Job { private String name; Make it compile private List<Step> steps; private Map<String, Object> args; •Public is default Map<String, Object> getArgs() { •Variables are return args; declared with var } void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } List<Step> getSteps() { return steps; •Functions declared } void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} String getName() { return name; •void ≈ Unit } •initialize var void setName(String name) { this.name = name; } }
    14. 14. class Job { private String name; Make it compile private List<Step> steps; private Map<String, Object> args; •Public is default Map<String, Object> getArgs() { •Variables are return args; declared with var } void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } List<Step> getSteps() { return steps; •Functions declared } void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} String getName() { return name; •void ≈ Unit } •initialize var void setName(String name) { this.name = name; } }
    15. 15. class Job { private String name; Make it compile private List<Step> steps; private Map<String, Object> args; •Public is default Map<String, Object> getArgs() { •Variables are return args; declared with var } void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } List<Step> getSteps() { return steps; •Functions declared } void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} String getName() { return name; •void ≈ Unit } •initialize var void setName(String name) { this.name = name; } }
    16. 16. class Job { private var String name; Make it compile private var List<Step> steps; private var Map<String, Object> args; •Public is default Map<String, Object> getArgs() { •Variables are return args; declared with var } void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } List<Step> getSteps() { return steps; •Functions declared } void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} String getName() { return name; •void ≈ Unit } •initialize var void setName(String name) { this.name = name; } }
    17. 17. class Job { private var String name; Make it compile private var List<Step> steps; private var Map<String, Object> args; •Public is default Map<String, Object> getArgs() { •Variables are return args; declared with var } void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } List<Step> getSteps() { return steps; •Functions declared } void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} String getName() { return name; •void ≈ Unit } •initialize var void setName(String name) { this.name = name; } }
    18. 18. class Job { private var String name; Make it compile private var List<Step> steps; private var Map<String, Object> args; •Public is default Map<String, Object> getArgs() { •Variables are return args; declared with var } void setArgs(Map<String, Object> args) { •Types after identifier •Generics with [] this.args = args; } List<Step> getSteps() { return steps; •Functions declared } void setSteps(List<Step> steps) { with def this.steps = steps; } •= {...} String getName() { return name; •void ≈ Unit } •initialize var void setName(String name) { this.name = name; } }
    19. 19. class Job { private var name:String; Make it compile private var steps:List<Step>; private var args:Map<String, Object>; •Public is default getArgs():Map<String, Object> { •Variables are return args; declared with var } setArgs(args:Map<String, Object>):void { •Types after identifier •Generics with [] this.args = args; } getSteps():List<Step> { return steps; •Functions declared } setSteps(steps:List<Step>):void { with def this.steps = steps; } •= {...} getName():String { return name; •void ≈ Unit } •initialize var setName(name:String):void { this.name = name; } }
    20. 20. class Job { private var name:String; Make it compile private var steps:List<Step>; private var args:Map<String, Object>; •Public is default getArgs():Map<String, Object> { •Variables are return args; declared with var } setArgs(args:Map<String, Object>):void { •Types after identifier •Generics with [] this.args = args; } getSteps():List<Step> { return steps; •Functions declared } setSteps(steps:List<Step>):void { with def this.steps = steps; } •= {...} getName():String { return name; •void ≈ Unit } •initialize var setName(name:String):void { this.name = name; } }
    21. 21. class Job { private var name:String; Make it compile private var steps:List<Step>; private var args:Map<String, Object>; •Public is default getArgs():Map<String, Object> { •Variables are return args; declared with var } setArgs(args:Map<String, Object>):void { •Types after identifier •Generics with [] this.args = args; } getSteps():List<Step> { return steps; •Functions declared } setSteps(steps:List<Step>):void { with def this.steps = steps; } •= {...} getName():String { return name; •void ≈ Unit } •initialize var setName(name:String):void { this.name = name; } }
    22. 22. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default getArgs():Map[String, Object] { •Variables are return args; declared with var } setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } getSteps():List[Step] { return steps; •Functions declared } setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} getName():String { return name; •void ≈ Unit } •initialize var setName(name:String):void { this.name = name; } }
    23. 23. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default getArgs():Map[String, Object] { •Variables are return args; declared with var } setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } getSteps():List[Step] { return steps; •Functions declared } setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} getName():String { return name; •void ≈ Unit } •initialize var setName(name:String):void { this.name = name; } }
    24. 24. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default getArgs():Map[String, Object] { •Variables are return args; declared with var } setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } getSteps():List[Step] { return steps; •Functions declared } setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} getName():String { return name; •void ≈ Unit } •initialize var setName(name:String):void { this.name = name; } }
    25. 25. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] { return steps; •Functions declared } def setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} def getName():String { return name; •void ≈ Unit } •initialize var def setName(name:String):void { this.name = name; } }
    26. 26. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] { return steps; •Functions declared } def setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} def getName():String { return name; •void ≈ Unit } •initialize var def setName(name:String):void { this.name = name; } }
    27. 27. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] { return steps; •Functions declared } def setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} def getName():String { return name; •void ≈ Unit } •initialize var def setName(name:String):void { this.name = name; } }
    28. 28. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] { return steps; •Functions declared } def setSteps(steps:List[Step]):void { with def this.steps = steps; } •= {...} def getName():String { return name; •void ≈ Unit } •initialize var def setName(name:String):void { this.name = name; } }
    29. 29. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):void = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):void = { this.name = name; } }
    30. 30. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):void = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):void = { this.name = name; } }
    31. 31. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):void = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):void = { this.name = name; } }
    32. 32. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):void = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):void = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):void = { this.name = name; } }
    33. 33. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    34. 34. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    35. 35. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    36. 36. class Job { private var name:String; Make it compile private var steps:List[Step]; private var args:Map[String, Object]; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    37. 37. class Job { private var name:String = null; Make it compile private var steps:List[Step] = null; private var args:Map[String, Object] = null; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    38. 38. class Job { private var name:String = null; Make it compile private var steps:List[Step] = null; private var args:Map[String, Object] = null; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    39. 39. class Job { private var name:String = null; Make it compile private var steps:List[Step] = null; private var args:Map[String, Object] = null; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    40. 40. class Job { private var name:String = null; Make it compile private var steps:List[Step] = null; private var args:Map[String, Object] = null; •Public is default def getArgs():Map[String, Object] = { •Variables are return args; declared with var } def setArgs(args:Map[String, Object]):Unit = { •Types after identifier •Generics with [] this.args = args; } def getSteps():List[Step] = { return steps; •Functions declared } def setSteps(steps:List[Step]):Unit = { with def this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    41. 41. class Job { private var name:String = null; Make it compile private var steps:List[Step] = null; •Public is default private var args:Map[String, Object] = null; def getArgs():Map[String, Object] = { •Variables are return args; declared with var } •Types after identifier def setArgs(args:Map[String, Object]):Unit = { •Generics with [] this.args = args; } IT COMPILES def getSteps():List[Step] = { return steps; •Functions declared } BUT IT’S JAVA WITH SCALA SYNTAX with def def setSteps(steps:List[Step]):Unit = { this.steps = steps; } •= {...} def getName():String = { return name; •void ≈ Unit } •initialize var def setName(name:String):Unit = { this.name = name; } }
    42. 42. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs():Map[String, Object] = { returned return args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps():List[Step] = { return steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName():String = { return name; } def setName(name:String):Unit = { this.name = name; } }
    43. 43. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs():Map[String, Object] = { returned return args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps():List[Step] = { return steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName():String = { return name; } def setName(name:String):Unit = { this.name = name; } }
    44. 44. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs():Map[String, Object] = { returned return args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps():List[Step] = { return steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName():String = { return name; } def setName(name:String):Unit = { this.name = name; } }
    45. 45. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs():Map[String, Object] = { returned args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps():List[Step] = { steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName():String = { name; } def setName(name:String):Unit = { this.name = name; } }
    46. 46. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs():Map[String, Object] = { returned args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps():List[Step] = { steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName():String = { name; } def setName(name:String):Unit = { this.name = name; } }
    47. 47. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs() = { returned args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps() = { steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName() = { name; } def setName(name:String):Unit = { this.name = name; } }
    48. 48. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs() = { returned args; } •Types are inferred def setArgs(args:Map[String, Object]):Unit = { •No = implies Unit •Single statement this.args = args; } def getSteps() = { steps; doesn’t need a block } def setSteps(steps:List[Step]):Unit = { •New line implies ; this.steps = steps; } def getName() = { name; } def setName(name:String):Unit = { this.name = name; } }
    49. 49. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs() = { returned args; } •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args; } def getSteps() = { steps; doesn’t need a block } def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps; } def getName() = { name; } def setName(name:String) { this.name = name; } }
    50. 50. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs() = { returned args; } •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args; } def getSteps() = { steps; doesn’t need a block } def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps; } def getName() = { name; } def setName(name:String) { this.name = name; } }
    51. 51. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs() = args; returned •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args; } def getSteps() = steps; doesn’t need a block def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps; } def getName() = name; def setName(name:String) { this.name = name; } }
    52. 52. class Job { private var name:String = null; Remove redundancy private var steps:List[Step] = null; private var args:Map[String, Object] = null; •The last statement is def getArgs() = args; returned •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args; } def getSteps() = steps; doesn’t need a block def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps; } def getName() = name; def setName(name:String) { this.name = name; } }
    53. 53. class Job { private var name:String = null Remove redundancy private var steps:List[Step] = null private var args:Map[String, Object] = null •The last statement is def getArgs() = args returned •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args } def getSteps() = steps doesn’t need a block def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps } def getName() = name def setName(name:String) { this.name = name } }
    54. 54. class Job { private var name:String = null Remove redundancy private var steps:List[Step] = null private var args:Map[String, Object] = null •The last statement is def getArgs() = args returned •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args } def getSteps() = steps doesn’t need a block def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps } def getName() = name def setName(name:String) { this.name = name } }
    55. 55. class Job { private var name:String = null Redundancy private var steps:List[Step] = null private var args:Map[String, Object] = null •The last statement is def getArgs() = args returned •Types are inferred def setArgs(args:Map[String, Object]) { •No = implies Unit •Single statement this.args = args } def getSteps() = steps doesn’t need a block def setSteps(steps:List[Step]) { •New line implies ; this.steps = steps } def getName() = name def setName(name:String) { this.name = name } }
    56. 56. class Job { private var name:String = null private var steps:List[Step] = null private var args:Map[String, Object] = null def getArgs() = args def setArgs(args:Map[String, Object]) { this.args = args } def getSteps() = steps There is an even shorter form! def setSteps(steps:List[Step]) { this.steps = steps } def getName() = name def setName(name:String) { this.name = name } }
    57. 57. class Job { import scala.reflect._ private var name:String = null class Job { private var steps:List[Step] = null @BeanProperty private var args:Map[String, Object] = null var name:String = null @BeanProperty def getArgs() = args var steps:List[Step] = null @BeanProperty var args:Map[String, Object] = null def setArgs(args:Map[String, Object]) { } this.args = args } def getSteps() = steps def setSteps(steps:List[Step]) { this.steps = steps } def getName() = name def setName(name:String) { this.name = name } }
    58. 58. public class Job { import scala.reflect._ private String name; class Job { private List<Step> steps; @BeanProperty private Map<String, Object> args; var name:String = null @BeanProperty public Map<String, Object> getArgs() { var steps:List[Step] = null return args; @BeanProperty } var args:Map[String, Object] = null public void setArgs(Map<String, Object> } args) { this.args = args; } public List<Step> getSteps() { return steps; } public void setSteps(List<Step> steps) { this.steps = steps; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
    59. 59. public class Job { import scala.reflect._ private String name; class Job { private List<Step> steps; @BeanProperty private Map<String, Object> args; var name:String = null @BeanProperty public Map<String, Object> getArgs() { var steps:List[Step] = null return args; @BeanProperty } var args:Map[String, Object] = null public void setArgs(Map<String, Object> } args) { this.args = args; SCALA SMALL } public List<Step> getSteps() { return steps; } public void setSteps(List<Step> steps) { this.steps = steps; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
    60. 60. public class Job { import scala.reflect._ private String name; class Job { private List<Step> steps; @BeanProperty private Map<String, Object> args; var name:String = null @BeanProperty public Map<String, Object> getArgs() { var steps:List[Step] = null return args; @BeanProperty } var args:Map[String, Object] = null public void setArgs(Map<String, Object> } More compact args) { this.args = args; } public List<Step> getSteps() { return steps; } But still a Java mindset public void setSteps(List<Step> steps) { this.steps = steps; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
    61. 61. import scala.reflect._ class Job { [Make it immutable] @BeanProperty var name:String = null •Add a constructor @BeanProperty var steps:List[Step] = null •Make fields immutable @BeanProperty var args:Map[String, Object] = null •Use default arguments •Create by name }
    62. 62. import scala.reflect._ class Job { [Make it immutable] @BeanProperty var name:String = null •Add a constructor @BeanProperty var steps:List[Step] = null •Make fields immutable @BeanProperty var args:Map[String, Object] = null •Use default arguments •Create by name }
    63. 63. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty var name:String, •Add a constructor @BeanProperty var steps:List[Step], •Make fields immutable @BeanProperty var args:Map[String, Object] •Use default arguments •Create by name ) { }
    64. 64. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty var name:String, •Add a constructor @BeanProperty var steps:List[Step], •Make fields immutable @BeanProperty var args:Map[String, Object] •Use default arguments •Create by name ) { }
    65. 65. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty val name:String, •Add a constructor @BeanProperty val steps:List[Step], •Make fields immutable @BeanProperty val args:Map[String, Object] •Use default arguments •Create by name ) { }
    66. 66. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty val name:String, •Add a constructor @BeanProperty val steps:List[Step], •Make fields immutable @BeanProperty val args:Map[String, Object] •Use default arguments •Create by name ) { }
    67. 67. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty val name:String = “no name”, •Add a constructor @BeanProperty val steps:List[Step] = emptyList, •Make fields immutable @BeanProperty val args:Map[String, Object] = •Use default emptyMap arguments •Create by name ) { }
    68. 68. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty val name:String = “no name”, •Add a constructor @BeanProperty val steps:List[Step] = emptyList, •Make fields immutable @BeanProperty val args:Map[String, Object] = •Use default emptyMap arguments •Create by name ) { }
    69. 69. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty val name:String = “no name”, •Add a constructor @BeanProperty val steps:List[Step] = emptyList, •Make fields immutable @BeanProperty val args:Map[String, Object] = •Use default emptyMap arguments •Create by name ) { } new Job ( name = “an empty job” )
    70. 70. import scala.reflect._ class Job ( [Make it immutable] @BeanProperty val name:String = “no name”, •Add a constructor @BeanProperty val steps:List[Step] = emptyList, •Make fields immutable @BeanProperty val args:Map[String, Object] = •Use default emptyMap arguments •Create by name ) { } new Job ( name = “an empty job” )
    71. 71. WHY SCALA?
    72. 72. WHY NOT JAVA?
    73. 73. JAVA HAS EVOLVED
    74. 74. 1.1 Inn er cla sse s 1.2 str co ictfp lle cti key on wo lib rd, rar re 1.4 ass y fle er cti tk on ey wo , En rd 1.5 an ums no , g tat en ion eri s, s cs, tat 1.7 Ho ic im JAVA HAS EVOLVED or ay po !P r ts ro jec tC oin !
    75. 75. 1.1 Inn er cla sse s 1.2 str co ictfp lle cti key on wo lib rd, rar re 1.4 ass y fle er cti tk on ey wo , En rd 1.5 an ums no , g tat en ion eri s, s cs, tat 1.7 Ho ic im JAVA HAS EVOLVED or ay po !P Good concepts have to be twisted to fit into Java ro r ts jec tC oin !
    76. 76. Java 1996 -2006
    77. 77. Java Coooooobooool 1996 -2006
    78. 78. Java 1996 -2006
    79. 79. WHY SCALA AGAIN? •Byte code compatible with Java •Designed for extendability •A higher level of abstraction
    80. 80. "If I'd asked my customers what they wanted, they'd have said a faster horse." - Henry Ford
    81. 81. PROJECT LAYOUT Java Scala Java Application Module Module
    82. 82. PROJECT LAYOUT JobControl.scala Java Scala Java Application Module Module
    83. 83. Exploit Scala public class JobControl { private JobFactory jf; Move a “logic” class public JobControl(JobFactory jf) { from Java to Scala so this.jf = jf; } that we can use Scala for more than just public void startJob(String name) { Job job = jf.create(name); beans if (job != null) { Map<String, Object> context = new HashMap<String, Object>(); for (Step step : job.getSteps()) { step.getCommand().run(context); } } } }
    84. 84. Exploit Scala class JobControl(jf:JobFactory) { Same steps as before def startJob(name:String) = { val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    85. 85. Exploit Scala class JobControl(jf:JobFactory) { Same steps as before Observe the for syntax def startJob(name:String) = { val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    86. 86. Exploit Scala class JobControl(jf:JobFactory) { Same steps as before Observe the for syntax def startJob(name:String) = { Does not compile, val job = jf.create(name) needs the result of if (job != null) { val context = getSteps to implement new HashMap[String, Object]() a foreach-method for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    87. 87. Exploit Scala class JobControl(jf:JobFactory) { Same steps as before Observe the for syntax def startJob(name:String) = { Does not compile, val job = jf.create(name) needs the result of if (job != null) { val context = getSteps to implement new HashMap[String, Object]() a foreach-method for (step <- job.getSteps()) { step.getCommand().run(context) } } Tip: Google for } } “structural typing”
    88. 88. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Scala 2.8 to the rescue: def startJob(name:String) = { val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    89. 89. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Scala 2.8 to the rescue: Implicit java conversions! def startJob(name:String) = { val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    90. 90. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Scala 2.8 to the rescue: Implicit java conversions! def startJob(name:String) = { val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    91. 91. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Scala 2.8 to the rescue: Implicit java conversions! def startJob(name:String) = { SCALA ☠ NULL val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    92. 92. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Scala 2.8 to the rescue: Implicit java conversions! def startJob(name:String) = { SCALA val job = jf.create(name) if (job != null) { val context = OPTIONS new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    93. 93. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Scala 2.8 to the rescue: Implicit java conversions! def startJob(name:String) = { val job = jf.create(name) if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    94. 94. trait JobFactory { def create(name:String):Job Exploit Scala Scala’s equivalent of interfaces: Traits }
    95. 95. trait JobFactory { def create(name:String):Job Exploit Scala def apply(name:String):Option[Job] Create an alternative method that optionally returns a Job As we will see, the name “apply” has a } special meaning in Scala
    96. 96. trait JobFactory { def create(name:String):Job Exploit Scala def apply(name:String):Option[Job] = { Traits can have val job = create(name) if (job == null) { implementations None } else { Mix ins: “Compiler copy Some(job) } + paste :)” } }
    97. 97. trait JobFactory { def create(name:String):Job Exploit Scala def apply(name:String):Option[Job] = { Traits can have val job = create(name) if (job == null) { implementations None } else { Mix ins: “Compiler copy Some(job) } + paste :)” } } Everything has a value in Scala!
    98. 98. trait JobFactory { def create(name:String):Job Exploit Scala def apply(name:String):Option[Job] = { Java will only see the val job = create(name) if (job == null) { interface so we need } None an adapter. else { Some(job) } An abstract base-class? } } abstract class AbstractJobFactory extends Object with JobFactory
    99. 99. trait JobFactory { def create(name:String):Job Exploit Scala def apply(name:String):Option[Job] = { Pattern-matching is val job = create(name) job match { more compact, more case null => None “scala” and can give you more compiler case job => Some(job) } support. } } NOT THE SAME AS abstract class AbstractJobFactory extends Object with JobFactory SWITCH CASE IN JAVA!!!
    100. 100. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Time to use our def startJob(name:String) = { val job = jf.create(name) “improved” factory if (job != null) { val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } } }
    101. 101. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { The option “enforces” def startJob(name:String) = { val job = jf.apply(name). handling the None- getOrElse(EMPTY_JOB) case. You can’t get the value unless you val context = new HashMap[String, Object]() provide what to return for (step <- job.getSteps()) { if the option is empty step.getCommand().run(context) } (None) } }
    102. 102. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { The option “enforces” def startJob(name:String) = { val job = jf.apply(name). handling the None- getOrElse(EMPTY_JOB) case. You can’t get the value unless you val context = new HashMap[String, Object]() provide what to return for (step <- job.getSteps()) { if the option is empty step.getCommand().run(context) } (None) } }
    103. 103. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { Told you the apply def startJob(name:String) = { val job = jf(name). name was special! getOrElse(EMPTY_JOB) val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } }
    104. 104. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { We can also execute def startJob(name:String) = { val job = jf(name). code if the option is getOrElse( {println(“hello”) empty error("No job with name: "+name)}) val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } }
    105. 105. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { We can also execute def startJob(name:String) = { val job = jf(name). code if the option is getOrElse( {println(“hello”) empty error("No job with name: "+name)}) val context = new HashMap[String, Object]() SCALA for (step <- job.getSteps()) { FUNCTIONS step.getCommand().run(context) } } }
    106. 106. SCALA FUNCTIONS
    107. 107. SCALA FUNCTIONS
    108. 108. SCALA FUNCTIONS AC DC
    109. 109. SCALA FUNCTIONS AC DC
    110. 110. SCALA FUNCTIONS AC DC
    111. 111. SCALA FUNCTIONS ( AC ) => DC
    112. 112. SCALA FUNCTIONS Type val transformer: ( AC ) => DC
    113. 113. SCALA FUNCTIONS ( AC ) => DC
    114. 114. SCALA FUNCTIONS ( String ) => Option[Job]
    115. 115. SCALA FUNCTIONS ( String ) => Option[Job] Function[String, Option[Job]]
    116. 116. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { We can also execute def startJob(name:String) = { val job = jf(name). code if the option is getOrElse( {println(“hello”) empty error("No job with name: "+name)}) val context = new HashMap[String, Object]() SCALA for (step <- job.getSteps()) { FUNCTIONS step.getCommand().run(context) } } }
    117. 117. import scala.collection.JavaConversions._ Exploit Scala class JobControl(jf:JobFactory) { We can also execute def startJob(name:String) = { val job = jf(name). code if the option is getOrElse( {println(“hello”) empty error("No job with name: "+name)}) val context = new HashMap[String, Object]() for (step <- job.getSteps()) { step.getCommand().run(context) } } }
    118. 118. trait JobFactory { Use functions Functions as Factories def create(name:String):Job def apply(name:String):Option[Job] = { Factories as Functions create(name) match { case null => None case job => Some(job) } } } abstract class AbstractJobFactory extends Object with JobFactory
    119. 119. trait JobFactory extends Function[String, Option[Job]] { Use functions def create(name:String):Job def apply(name:String):Option[Job] = { Functions are objects create(name) match { and can be extended case null => None case job => Some(job) } We already implement } } apply abstract class AbstractJobFactory extends Object with JobFactory
    120. 120. import scala.collection.JavaConversions._ Use functions class JobControl(jf:JobFactory) { def startJob(name:String) = { val job = jf(name). We can now change val context = getOrElse(EMPTY_JOB) our dependencies from new HashMap[String, Object]() JobControl... for (step <- job.getSteps()) { step.getCommand().run(context) } } }
    121. 121. import scala.collection.JavaConversions._ Use functions class JobControl(jf:JobFactory) { def startJob(name:String) = { val job = jf(name). We can now change val context = getOrElse(EMPTY_JOB) our dependencies from new HashMap[String, Object]() JobControl... for (step <- job.getSteps()) { step.getCommand().run(context) } } }
    122. 122. import scala.collection.JavaConversions._ Use functions class JobControl(jf:(String)=>Option[Job]) { def startJob(name:String) = { val job = jf(name). Let’s depend on a val context = getOrElse(EMPTY_JOB) function instead of a new HashMap[String, Object]() factory for (step <- job.getSteps()) { step.getCommand().run(context) } } }
    123. 123. FUNCTIONS AS FACTORIES def emptyJobFactory(name:String) = { Some(new Job(name, emptyJavaList, emptyJavaMap)) } new JobControl(emptyJobFactory)
    124. 124. PROJECT LAYOUT Java Scala Java Application Module Module
    125. 125. PROJECT LAYOUT Main.java Java Scala Java Application Module Module
    126. 126. STILL A FACTORY IN JAVA! Defined in Java public static void main(String[] args) { Defined in Scala JobFactory factory = new JdbcJobFactory(); JobControl control = new JobControl(factory); ... }
    127. 127. STILL A FACTORY IN JAVA! public static void main(String[] args) { JobFactory factory = new JdbcJobFactory(); SCALA JAVA JobControl control = new JobControl(factory); ... }
    128. 128. STILL A FACTORY IN JAVA! public static void main(String[] args) { JobFactory factory = new JdbcJobFactory(); JobControl control = new JobControl(factory); ... }
    129. 129. IN CONCLUSION You don’t have to use everything Scala has to offer right away! You don’t even have to understand ALL the concepts of Scala to start coding Scala
    130. 130. IN CONCLUSION It’s EASY to start programming Scala... It’s HARD to stop!
    131. 131. YOU HAVE BEEN WATCHING
    132. 132. YOU HAVE BEEN WATCHING Enno Runne email: enno@runne.net hlr ogge gical.com im O ogge@a Joak .ohlr joa kim ogge press.com ohlr ord : @j itter lrogge.w tw http://a ttp:/ /joh gical.co h http://a m/reso gical.co urces/a http://a m/reso r ticles/ gical.co urces/a s4jp.pd m/reso r ticles/ f urces/a s4jp.m r ticles/ ov s4jp.ke y

    ×