Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

Effective Java with Groovy - How Language can Influence Good Practices

Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Nächste SlideShare
16. Java stacks and queues
16. Java stacks and queues
Wird geladen in …3
×

Hier ansehen

1 von 88 Anzeige

Effective Java with Groovy - How Language can Influence Good Practices

Herunterladen, um offline zu lesen

Slide from my GIDS 2019 talk - Effective Java with Groovy - How Language can Influence Good Practices among Developers.

Slide from my GIDS 2019 talk - Effective Java with Groovy - How Language can Influence Good Practices among Developers.

Anzeige
Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Ähnlich wie Effective Java with Groovy - How Language can Influence Good Practices (20)

Anzeige

Weitere von Naresha K (20)

Aktuellste (20)

Anzeige

Effective Java with Groovy - How Language can Influence Good Practices

  1. 1. Effective Java with Groovy - How language can Influence Good Practices Naresha K, Technical Excellence Coach | Consultant | Agile & Cloud Transformation Catalyst @naresha_k https://blog.nareshak.com/
  2. 2. About Me
  3. 3. http://nareshak.blogspot.com/
  4. 4. http://nareshak.blogspot.com/
  5. 5. !7 https://www.flickr.com/photos/hchalkley/30724738
  6. 6. !8 Data Information Knowledge Wisdom
  7. 7. !9 https://www.flickr.com/photos/drauh/2456223489
  8. 8. !10
  9. 9. !11http://radio-weblogs.com/0112098/2003/08/29.html initial idea was to make a little dynamic language which compiles directly to Java classes and provides all the nice (alleged) productivity benefits - James Strachan
  10. 10. Know Your Path The problem/ Context What does ‘Effective Java’ say? The traps Groovier Solution Lessons Learned !12 Tool Wisdom
  11. 11. !13 https://www.flickr.com/photos/twid/410697715
  12. 12. !14 class Product { Long id String code String name BigDecimal price static constraints = { code unique: true } }
  13. 13. P #1 !15 def actionE1(){ Product p = new Product(code: 'P101', name: 'Effective Java', price: 499.00) p.save(flush: true) render p } def actionE2(){ Product p = new Product(code: 'P101', name: 'Effective Java', price: 499.00) Product p2 = Product.findByCode('P101') render p == p2 } false
  14. 14. P #2 !16 def actionH1(){ Product p = new Product(code: 'P102', name: 'Programming Groovy 2', price: 2217.78) p.save(flush: true) def stock = [:] stock[p] = 100 session.setAttribute('stock', stock) render stock } def actionH2(){ def stock = session.getAttribute('stock') println stock Product p = new Product(code: 'P102', name: 'Programming Groovy 2', price: 2217.78) render stock[p] } null
  15. 15. !17
  16. 16. !18 #8: Obey the general contract when overriding equals #9: Always override hashCode when you override equals
  17. 17. !19 import groovy.transform.EqualsAndHashCode @EqualsAndHashCode(includes='id') class Product { Long id String code String name BigDecimal price static constraints = { code unique: true } }
  18. 18. !20 import groovy.transform.EqualsAndHashCode @EqualsAndHashCode(includes=‘code') class Product { Long id String code String name BigDecimal price static constraints = { code unique: true } }
  19. 19. P #1 !21 def actionE1(){ Product p = new Product(code: 'P101', name: 'Effective Java', price: 499.00) p.save(flush: true) render p } def actionE2(){ Product p = new Product(code: 'P101', name: 'Effective Java', price: 499.00) Product p2 = Product.findByCode('P101') render p == p2 } true
  20. 20. P #2 !22 def actionH1(){ Product p = new Product(code: 'P102', name: 'Programming Groovy 2', price: 2217.78) p.save(flush: true) def stock = [:] stock[p] = 100 session.setAttribute('stock', stock) render stock } def actionH2(){ def stock = session.getAttribute('stock') println stock Product p = new Product(code: 'P102', name: 'Programming Groovy 2', price: 2217.78) render stock[p] } 100
  21. 21. !23 AST Transformation Single point of representation for any knowledge
  22. 22. !24 List<Integer> numbers = Arrays.asList(10, 20, 30, 40); for(int i=0; i<numbers.size(); i++){ System.out.println(numbers.get(i)); }
  23. 23. !25 http://upload.wikimedia.org/wikipedia/commons/8/82/Cable_closet_bh.jpg
  24. 24. !26 #46: Prefer for-each loops to traditional for loops
  25. 25. !27 def numbers = [10, 20, 30, 40] def sum = 0 for(int number in numbers){ sum += number } println "Sum: " + sum
  26. 26. !28 numbers.each{ number-> println number } println numbers.collect { number -> number * 2 } println numbers.inject(0, {result, number -> result + number } ) 10 20 30 40 [20, 40, 60, 80] 100
  27. 27. !29 Closures Favor Internal iterators to external iterators Minimize the moving parts in your code
  28. 28. !30 public static void main( String[] args ) { float price = 0.1f; float total = 0; for(int i=0; i<10; i++){ total += price; } System.out.println("Total: " + total); } Total: 1.0000001
  29. 29. !31 public static void main( String[] args ) { double price = 0.1; double total = 0; for(int i=0; i<10; i++){ total += price; } System.out.println("Total: " + total); } Total: 0.9999999999999999
  30. 30. !32 #48: Avoid float and double if exact answers are required
  31. 31. !33 public static void main( String[] args ) { BigDecimal price = new BigDecimal(0.1); BigDecimal total = new BigDecimal(0); for(int i=0; i<10; i++){ total = total.add(price); } System.out.println("Total: " + total); } Total: 1.000000000000000055511151231257827021181 5834045410156250
  32. 32. !34 public static void main( String[] args ) { BigDecimal price = new BigDecimal(“0.1”); BigDecimal total = new BigDecimal(0); for(int i=0; i<10; i++){ total = total.add(price); } System.out.println("Total: " + total); } Total: 1.0
  33. 33. !35 def price = 0.1 def total = 0 10.times { total += price } println "Total: " + total Total: 1.0
  34. 34. !36 Principle Of Least Astonishment Select appropriate default
  35. 35. !37 [1, 3, 4, 8, 16, 9] •Find all even numbers •Find all odd numbers •Find numbers divisible by 4 •Find numbers greater than 5
  36. 36. !38 #21: Use function objects to represent strategies
  37. 37. !39 interface Filter{ def includes(number) } class OddFilter implements Filter{ def includes(number){ number % 2 != 0 } } class DivisibleBy4Filter implements Filter{ def includes(number){ number % 4 == 0 } } def doFilter(numbers, Filter filter){ def filteredValues = [] for(int number in numbers){ if(filter.includes(number)){ filteredValues << number } } filteredValues } println doFilter(numbers, new OddFilter()) println doFilter(numbers, new DivisibleBy4Filter())
  38. 38. !40 def divisibleBy4 = { number -> number % 4 == 0 } def odd = { number -> number % 2 != 0 } def numbers = [1, 3, 4, 8, 16, 9] println "Odd numbers: " + numbers.findAll(odd) println "Div by 4: " + numbers.findAll(divisibleBy4) Odd numbers: [1, 3, 9] Div by 4: [4, 8, 16]
  39. 39. !41 Closures No boilerplate code polymorphic code reading skill not required Less duplicate code (potentially)
  40. 40. Bring in Order !42 @ToString class Person { String name int age } def geeks = [ new Person(name: 'Arun', age: 35), new Person(name: 'Raj', age: 30), new Person(name: 'Abhi', age: 35), new Person(name:'Kumar', age: 32), new Person(name: 'Kumar', age: 25) ]
  41. 41. !43 #12: Consider implementing Comparable
  42. 42. !44 println 10 <=> 20 println 20 <=> 10 println 10 <=> 10 -1 1 0
  43. 43. !45 @ToString class Person implements Comparable<Person>{ String name int age int compareTo(Person other){ name <=> other.name } }
  44. 44. Default Sort Order !46 println geeks.sort(false) Original: [ Person(Arun, 35), Person(Raj, 30), Person(Abhi, 35), Person(Kumar, 32), Person(Kumar, 25) ] Sorted: [ Person(Abhi, 35), Person(Arun, 35), Person(Kumar, 32), Person(Kumar, 25), Person(Raj, 30) ]
  45. 45. Sort by Age !47 println geeks.sort(false) { a, b -> a.age <=> b.age} Original: [ Person(Arun, 35), Person(Raj, 30), Person(Abhi, 35), Person(Kumar, 32), Person(Kumar, 25) ] Sorted: [ Person(Kumar, 25), Person(Raj, 30), Person(Kumar, 32), Person(Arun, 35), Person(Abhi, 35) ]
  46. 46. Sort by age, name !48 int compareTo(Person other) { if (this.is(other)) { return 0 } java.lang.Integer value = 0 value = this .name <=> other .name if ( value != 0) { return value } value = this .age <=> other .age if ( value != 0) { return value } return 0 }
  47. 47. Sort by age, name !49 println geeks.sort(false, { a, b -> [{it.age}, {it.name}].findResult { c -> c(a) <=> c(b) ?: null } }) Original: [ Person(Arun, 35), Person(Raj, 30), Person(Abhi, 35), Person(Kumar, 32), Person(Kumar, 25) ] Sorted: [ Person(Kumar, 25), Person(Raj, 30), Person(Kumar, 32), Person(Abhi, 35), Person(Arun, 35) ]
  48. 48. Sort by age, name !50 Original: [ Person(Arun, 35), Person(Raj, 30), Person(Abhi, 35), Person(Kumar, 32), Person(Kumar, 25) ] Sorted: [ Person(Kumar, 25), Person(Raj, 30), Person(Kumar, 32), Person(Abhi, 35), Person(Arun, 35) ] @Sortable(includes = "name, age") @ToString class Person { String name int age }
  49. 49. !51 Syntactic Sugar - Spaceship Operator Simplify common tasks
  50. 50. Million Dollar Effort? !52 ?
  51. 51. Million Dollar Effort !!! !53 null
  52. 52. !54 def List<Speaker> getSpeakers(String conference){ null } def gidsSpeakers = getSpeakers('GIDS19') if(gidsSpeakers != null){ }
  53. 53. !55 #43: Return empty arrays or collections, not nulls
  54. 54. !56 def numbers = [2, 3, 1, 4] println numbers.collect { it + 1} [3, 4, 2, 5] numbers = [] println numbers.collect { it + 1} [] println numbers .findAll { it % 2 == 0} .collect { it * 2} .sum()
  55. 55. !57 println null.collect { it } [] println null.collect { it }.sum() null Caught: java.lang.NullPointerException: Cannot invoke method sum() on null object println null.collect { it }.sum() println null.sum()
  56. 56. !58
  57. 57. !59 NullObject No boilerplate code Life is too short for null checks
  58. 58. !60
  59. 59. !61 #3: Enforce the singleton property with a private constructor or an enum type
  60. 60. !62 class Manager{ private static final Manager manager = new Manager() private Manager(){ super() } static Manager getInstance(){ manager } } def m1 = Manager.getInstance() def m2 = Manager.getInstance() println m1 == m2 true
  61. 61. !63 class Manager{ private static final Manager manager = new Manager() private Manager(){ super() } static Manager getInstance(){ manager } } def m = new Manager() println m Manager@12e61fe6
  62. 62. !64 @Singleton class Manager{ } def m1 = Manager.getInstance() def m2 = Manager.getInstance() println m1 == m2 def m = new Manager() println m Caught: java.lang.RuntimeException: Can't instantiate singleton Manager. Use Manager.instance
  63. 63. !65 private static Manager manager static Manager getInstance(){ if(!manager){ manager = new Manager() } manager }
  64. 64. !66 private static Manager manager static synchronized Manager getInstance(){ if(!manager){ manager = new Manager() } manager }
  65. 65. !67 @Singleton(lazy=true) class Manager{ } println Manager.@instance def m1 = Manager.getInstance() println Manager.@instance null Manager@12e61fe6
  66. 66. !68 @Singleton(lazy=true) class Manager{ } println Manager.@instance def m1 = Manager.getInstance() println Manager.@instance null Manager@12e61fe6
  67. 67. !69
  68. 68. !70 private static volatile Manager instance public static Manager getInstance() { if ( instance != null) { return instance } else { synchronized (Manager) { if ( instance != null) { return instance } else { return instance = new Manager() } } } }
  69. 69. !71 YAGNI Premature optimisation is the root of all evil Don’t punish the punctual AST Transformation
  70. 70. !72 https://www.flickr.com/photos/38080114@N07/8594601982/
  71. 71. !73 #15: Minimize Mutability
  72. 72. Rules to make a class mutable • Don’t provide any mutators • Ensure that the class can’t be extended • Make all fields final • Make all fields private • Ensure exclusive access to any mutable components !74
  73. 73. !75 class ImmutableClass{ private final def field1 private final def field2 //... private final def field10 public ImmutableClass(f1, f2,… f10){ //initialization } }
  74. 74. !76 import groovy.transform.Immutable @Immutable class Rectangle{ int length int breadth } def r = new Rectangle(length: 10, breadth: 5) println r // Rectangle(10, 5)
  75. 75. !77
  76. 76. Code !78 public Rectangle(java.util.HashMap args) { metaClass = /*BytecodeExpression*/ if ( args .length == null) { } else { this .length = (( args .length) as int) } if ( args .breadth == null) { } else { this .breadth = (( args .breadth) as int) } }
  77. 77. !79 Syntactic Sugar Readability Matters AST Transformation
  78. 78. !80
  79. 79. !81 #15: Favour composition over inheritance
  80. 80. !82 class PhoneNumbers{ private @Delegate List phoneNumbers PhoneNumbers(numbers){ phoneNumbers = numbers } def bengaluruNumbers(){ phoneNumbers.findAll { it.startsWith('80') } } }
  81. 81. !83 def ph = ['9812312345', '9812312346', '802312347'] as PhoneNumbers println ph println ph.find { it == '9812312345'} println ph.find { it.endsWith('6') } println ph.bengaluruNumbers()
  82. 82. Traits trait CanSing { def sing() { println "Singing" } } trait CanDance { def dance() { println "Dancing" } } class Person implements CanSing, CanDance {} Person reema = new Person() reema.sing() reema.dance()
  83. 83. !85 AST Transformation Simplify Traits
  84. 84. Take Away Some of the ‘Effective Java’ already built into the language AST Transformations reduce the effort to implement few more Effective Java implementations may not always be effective Groovy implementations (Traps) !86
  85. 85. Take Away Programming languages can reduce the friction to implement good practices !87
  86. 86. Thank You

×