Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Groovy in the light of Java 8 -- JavaOne 2014

Groovy in the light of Java 8 -- JavaOne 2014

With Java 8 out, what is the impact of Groovy? Is it still relevant? How can developers can benefit from Java 8 with Groovy?

Guillaume Laforge

October 02, 2014
Tweet

More Decks by Guillaume Laforge

Other Decks in Programming

Transcript

  1. But more precisely… • Will Java lambdas replace Groovy closures?

    • What are the differences between them? ! • Will Groovy support all the new Java 8 language constructs? • lambdas, default methods, method references… ! • How Groovy developers can benefit from Java 8? ! • What does Groovy offer beyond Java 8? 6
  2. What about redundancy? ! ! ! ! ! • Closures

    • Traits • Truth & null handling • Functional with collections • Method closures ! ! ! ! ! ! • Lambdas • Default methods • Optional • Stream API • Method references 7
  3. This is not a Java 8 crash courses with all

    the details :-) We want to understand the implications with regards to Groovy
  4. What’s new in Java 8? ! • New syntax •

    Streams • Profiles • Security enhancements • JavaFX • Tools • i18n • Date / time API • Nashorn / JavaScript ! ! • Pack200 • IO / NIO improvements • New utility classes • JDBC • Networking • Concurrency • JAXP • Hotspot • Java Mission Control 10
  5. What’s new in Java 8? ! • New syntax •

    Streams • Profiles • Security enhancements • JavaFX • Tools • i18n • Date / time API • Nashorn / JavaScript ! ! • Pack200 • IO / NIO improvements • New utility classes • JDBC • Networking • Concurrency • JAXP • Hotspot • Java Mission Control 10 Great concise resource with the whole list: http://bit.ly/new-in-java-8
  6. @glaforge — Groovy in the light of Java 8 Support

    the new Java 8 language features New Java 8 syntax
  7. New Java 8 syntax constructs • Lambda expressions • Method

    references • Static & default methods in interfaces • Repeating annotations • Annotations on types • Improved type inference • Method parameter reflection 12
  8. New Java 8 syntax constructs • Lambda expressions • Method

    references • Static & default methods in interfaces • Repeating annotations • Annotations on types • Improved type inference • Method parameter reflection 13
  9. Lambda expressions 15 double highestScore = students .filter(Student s ->

    s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();
  10. Lambda expressions 16 double highestScore = students .filter(Student s ->

    s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();
  11. Lambda expressions 16 double highestScore = students .filter(Student s ->

    s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max(); Coercion into a Predicate « functional interface »
  12. Lambda expressions 16 double highestScore = students .filter(Student s ->

    s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max(); There’s no function type!
  13. Lambda expressions 16 double highestScore = students .filter(Student s ->

    s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max(); Pipeline being built Single pass!
  14. Lambda expressions 16 double highestScore = students .filter(Student s ->

    s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();
  15. Lambda expressions 17 double highestScore = students .findAll { it.gradYear

    == 2011 } .collect { it.score} .max() In Groovy, that would be…
  16. Lambda expressions 17 double highestScore = students .findAll { it.gradYear

    == 2011 } .collect { it.score} .max() Drawback: intermediary data structures Unless you use iterator variants
  17. The various lambda syntaxes 18 String name -> name.length() !

    (int left, int right) -> left + right ! (String left, String sep, String right) -> { System.out.println(left + sep + right) }
  18. The various lambda syntaxes 18 String name -> name.length() !

    (int left, int right) -> left + right ! (String left, String sep, String right) -> { System.out.println(left + sep + right) } One parameter: no parens Expression on right: no curly
  19. The various lambda syntaxes 18 String name -> name.length() !

    (int left, int right) -> left + right ! (String left, String sep, String right) -> { System.out.println(left + sep + right) } Parentheses required for more that one parameter
  20. The various lambda syntaxes 18 String name -> name.length() !

    (int left, int right) -> left + right ! (String left, String sep, String right) -> { System.out.println(left + sep + right) } Statements require curly braces Return keyword required if non-void returning
  21. The various lambda syntaxes 18 String name -> name.length() !

    (int left, int right) -> left + right ! (String left, String sep, String right) -> { System.out.println(left + sep + right) } Clever type inference can help get rid of parameter type declarations
  22. Closures vs lambdas 19 IntStream.range(1, 100).forEach(s -> System.out.println(s)); ! Files.lines(Paths.get('README.adoc'))

    .map(it -> it.toUpperCase()) .forEach(it -> System.out.println(it)); IntStream.range(1, 100).forEach { println it } ! Files.lines(Paths.get('README.adoc')) .map { it.toUpperCase() } .forEach { println it }
  23. Closures vs lambdas 19 IntStream.range(1, 100).forEach(s -> System.out.println(s)); ! Files.lines(Paths.get('README.adoc'))

    .map(it -> it.toUpperCase()) .forEach(it -> System.out.println(it)); IntStream.range(1, 100).forEach { println it } ! Files.lines(Paths.get('README.adoc')) .map { it.toUpperCase() } .forEach { println it } Use Groovy closures wherever you pass lambdas in Java 8
  24. Closures vs lambdas 19 IntStream.range(1, 100).forEach(s -> System.out.println(s)); ! Files.lines(Paths.get('README.adoc'))

    .map(it -> it.toUpperCase()) .forEach(it -> System.out.println(it)); IntStream.range(1, 100).forEach { println it } ! Files.lines(Paths.get('README.adoc')) .map { it.toUpperCase() } .forEach { println it } Groovy coerces to SAM types (Single Abstract Method)
  25. Closures vs lambdas 19 IntStream.range(1, 100).forEach(s -> System.out.println(s)); ! Files.lines(Paths.get('README.adoc'))

    .map(it -> it.toUpperCase()) .forEach(it -> System.out.println(it)); IntStream.range(1, 100).forEach { println it } ! Files.lines(Paths.get('README.adoc')) .map { it.toUpperCase() } .forEach { println it }
  26. Beyond: Closure default parameters 20 def mult = { int

    a, int b = 10 -> a * b } ! assert mult(2, 3) == 6 assert mult(5) == 50
  27. Beyond: Closure default parameters 20 def mult = { int

    a, int b = 10 -> a * b } ! assert mult(2, 3) == 6 assert mult(5) == 50 Default value if the parameter is not specified
  28. Beyond: Duck typing polymorphism 21 def adder = { a,

    b -> a + b } ! assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY'
  29. Beyond: Duck typing polymorphism 21 def adder = { a,

    b -> a + b } ! assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' Works both for numbers and for strings
  30. Lambda-based builders uglier and less powerful 23 MarkupBuilder pom =

    new XmlMarkupBuilder() pom.el("modelVersion", "4.0.0"); pom.el("groupId", "com.github"); pom.el("artifactId", "lambda-builder"); pom.el("version", "1.0-SNAPSHOT"); pom.el("dependencies", () -> { pom.el("dependency", () -> { pom.el("groupId", "junit"); pom.el("artifactId", "junit"); pom.elx("version", "4.11"); }); pom.el("dependency", () -> { pom.el("groupId", "commons-beanutils"); pom.el("artifactId", "commons-beanutils"); pom.elx("version", "1.7.0"); }); });
  31. Lambda-based builders uglier and less powerful 23 MarkupBuilder pom =

    new XmlMarkupBuilder() pom.el("modelVersion", "4.0.0"); pom.el("groupId", "com.github"); pom.el("artifactId", "lambda-builder"); pom.el("version", "1.0-SNAPSHOT"); pom.el("dependencies", () -> { pom.el("dependency", () -> { pom.el("groupId", "junit"); pom.el("artifactId", "junit"); pom.elx("version", "4.11"); }); pom.el("dependency", () -> { pom.el("groupId", "commons-beanutils"); pom.el("artifactId", "commons-beanutils"); pom.elx("version", "1.7.0"); }); }); Repeated « pom »: No delegate like in Groovy’s closures
  32. Lambda-based builders uglier and less powerful 23 MarkupBuilder pom =

    new XmlMarkupBuilder() pom.el("modelVersion", "4.0.0"); pom.el("groupId", "com.github"); pom.el("artifactId", "lambda-builder"); pom.el("version", "1.0-SNAPSHOT"); pom.el("dependencies", () -> { pom.el("dependency", () -> { pom.el("groupId", "junit"); pom.el("artifactId", "junit"); pom.elx("version", "4.11"); }); pom.el("dependency", () -> { pom.el("groupId", "commons-beanutils"); pom.el("artifactId", "commons-beanutils"); pom.elx("version", "1.7.0"); }); }); Zero-arg lamdas not as lean
  33. Lambda-based builders uglier and less powerful 23 MarkupBuilder pom =

    new XmlMarkupBuilder() pom.el("modelVersion", "4.0.0"); pom.el("groupId", "com.github"); pom.el("artifactId", "lambda-builder"); pom.el("version", "1.0-SNAPSHOT"); pom.el("dependencies", () -> { pom.el("dependency", () -> { pom.el("groupId", "junit"); pom.el("artifactId", "junit"); pom.elx("version", "4.11"); }); pom.el("dependency", () -> { pom.el("groupId", "commons-beanutils"); pom.el("artifactId", "commons-beanutils"); pom.elx("version", "1.7.0"); }); }); Generic method + string: No dynamic method
  34. Neater Groovy builder! 24 def pom = new PomBuilder().project {

    modelVersion "4.0.0" groupId "com.github" artifactId "lambda-builder" version "1.0-SNAPSHOT" dependencies { dependency { groupId "junit" artifactId "junit" version "4.11" } dependency { groupId "commons-beanutils" artifactId "commons-beanutils" version "1.7.0" } } }
  35. Neater Groovy builder! 24 def pom = new PomBuilder().project {

    modelVersion "4.0.0" groupId "com.github" artifactId "lambda-builder" version "1.0-SNAPSHOT" dependencies { dependency { groupId "junit" artifactId "junit" version "4.11" } dependency { groupId "commons-beanutils" artifactId "commons-beanutils" version "1.7.0" } } }
  36. Closure and method memoization 28 def fib2 = { long

    n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize()
  37. Closure and method memoization 28 def fib2 = { long

    n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize() Closures: memoize()
  38. Closure and method memoization 28 @Memoized long fib(long n) {

    if (n < 2) 1 else fib(n - 1) + fib(n - 2) } def fib2 = { long n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize() Closures: memoize()
  39. Closure and method memoization 28 @Memoized long fib(long n) {

    if (n < 2) 1 else fib(n - 1) + fib(n - 2) } def fib2 = { long n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize() Closures: memoize() Methods: memoization AST transformation
  40. Closure and method tail recursion 30 def fact = {

    n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline()
  41. Closure and method tail recursion 30 def fact = {

    n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline() Closures: Tail recursion with trampoline()
  42. Closure and method tail recursion 30 @groovy.transform.TailRecursive def fact(n, accu

    = 1G) { if (n < 2) accu else fact(n - 1, n * accu) } def fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline() Closures: Tail recursion with trampoline()
  43. Closure and method tail recursion 30 @groovy.transform.TailRecursive def fact(n, accu

    = 1G) { if (n < 2) accu else fact(n - 1, n * accu) } def fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline() Closures: Tail recursion with trampoline() Methods: Tail recursion with @TailRecursive transformation
  44. Method references — 3 main cases • Three main cases:

    32 instance::instanceMethod ! SomeClass::staticMethod ! SomeClass::instanceMethod
  45. Method references — 3 main cases • Three main cases:

    32 instance::instanceMethod ! SomeClass::staticMethod ! SomeClass::instanceMethod Not covered by Groovy method closures yet!
  46. Static methods in interfaces • You can put static utility

    methods in interfaces, 
 instead of in companion classes (like « Collections ») 34 public interface Stream<T> { // ... static <T> Stream<T> empty() { return new Stream<T> { ... } } }
  47. Default methods in interfaces • Define default behavior • possibly

    to enrich existing interfaces 35 public interface Stream<T> { // ... default Builder<T> add(T t) { ... } }
  48. Groovy Traits • Like interfaces, but with method bodies •

    similar to Java 8 interface default methods • Elegant way to compose behavior • multiple inheritance without the « diamond » problem • Traits can also be stateful • traits can have properties like normal classes • Compatible with static typing and static compilation • class methods from traits also visible from Java classes • Also possible to implement traits at runtime 36
  49. Simple trait 37 trait FlyingAbility { String fly() { "I'm

    flying!" } } ! class Bird implements FlyingAbility {} def b = new Bird() ! assert b.fly() == "I'm flying!"
  50. Trait with state 38 trait Named { String name }

    ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri'
  51. Multiple inheritance 39 trait KiteSurfer { String surf() { 'kite'

    } } ! trait WebSurfer { String surf() { 'web' } } ! class Person { String name } ! class Hipster extends Person implements KiteSurfer, WebSurfer {} ! def h = new Hipster() assert h.surf() == 'web'
  52. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Schedule annotation repeated twice
  53. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; }
  54. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; } Container annotation for the repeated annotationd
  55. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; } public @interface Schedules { Schedule[] value(); }
  56. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; } public @interface Schedules { Schedule[] value(); } The container annotation iteself
  57. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; } public @interface Schedules { Schedule[] value(); }
  58. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; } public @interface Schedules { Schedule[] value(); } Not yet supported
  59. Repeating annotations 41 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek = "Fri", hour

    = 23) public void doPeriodicCleanup() { ... } @Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; } public @interface Schedules { Schedule[] value(); }
  60. Annotations on types • Everywhere you can put a type,

    you can put an annotation 42 @NonNull String name; ! email = (@Email String) input; ! List<@NonNull String> names; ! new @Interned MyObject(); ! void monitorTemperature() throws @Critical TemperatureException { ... } ! class UnmodifiableList<T> implements @Readonly List<@Readonly T> {...}
  61. Annotations on types • Everywhere you can put a type,

    you can put an annotation 42 @NonNull String name; ! email = (@Email String) input; ! List<@NonNull String> names; ! new @Interned MyObject(); ! void monitorTemperature() throws @Critical TemperatureException { ... } ! class UnmodifiableList<T> implements @Readonly List<@Readonly T> {...} Not yet supported
  62. Annotations on types • Everywhere you can put a type,

    you can put an annotation 42 @NonNull String name; ! email = (@Email String) input; ! List<@NonNull String> names; ! new @Interned MyObject(); ! void monitorTemperature() throws @Critical TemperatureException { ... } ! class UnmodifiableList<T> implements @Readonly List<@Readonly T> {...} Imagine the potential for targets for local AST transformations?
  63. Annotations on types • Everywhere you can put a type,

    you can put an annotation 42 @NonNull String name; ! email = (@Email String) input; ! List<@NonNull String> names; ! new @Interned MyObject(); ! void monitorTemperature() throws @Critical TemperatureException { ... } ! class UnmodifiableList<T> implements @Readonly List<@Readonly T> {...}
  64. Groovy compile-time meta-annotations 43 @Service @Transactional class MyTransactionalService {} import

    groovy.transform.AnnotationCollector ! @Service @Transactional @AnnotationCollector public @interface TransactionalService {}
  65. Groovy compile-time meta-annotations 43 import groovy.transform.AnnotationCollector ! @Service @Transactional @AnnotationCollector

    public @interface TransactionalService {} ! @TransactionalService class MyTransactionalService {}
  66. Groovy compile-time meta-annotations 43 import groovy.transform.AnnotationCollector ! @Service @Transactional @AnnotationCollector

    public @interface TransactionalService {} ! @TransactionalService class MyTransactionalService {} Can handle parameters (even conflicting), or you can create your own « processor »
  67. Groovy compile-time meta-annotations 43 import groovy.transform.AnnotationCollector ! @Service @Transactional @AnnotationCollector

    public @interface TransactionalService {} ! @TransactionalService class MyTransactionalService {}
  68. Date / Time API 46 LocalDate.now(); today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2); ! LocalDate.of(2012, Month.MAY,

    14); dateOfBirth.plusYears(1); ! LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 20); LocalDate nextWed = date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
  69. Date / Time API 46 LocalDate.now(); today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2); ! LocalDate.of(2012, Month.MAY,

    14); dateOfBirth.plusYears(1); ! LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 20); LocalDate nextWed = date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY)); Groovy could add some operator overloading?
  70. Date / Time API 46 LocalDate.now(); today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2); ! LocalDate.of(2012, Month.MAY,

    14); dateOfBirth.plusYears(1); ! LocalDate date = LocalDate.of(2000, Month.NOVEMBER, 20); LocalDate nextWed = date.with(TemporalAdjusters.next(DayOfWeek.WEDNESDAY));
  71. Groovy’s date / time handling 47 import static java.util.Calendar.* import

    groovy.time.* import org.codehaus.groovy.runtime.TimeCategory ! def cal = Calendar.instance cal.set(year: 2010, month: JULY, date: 9) ! assert FRIDAY == cal[DAY_OF_WEEK] ! use (TimeCategory) { 2.years + 3.months + 15.days + 23.minutes + 2.seconds ! 1.week - 1.day new Date() + 6.days ! 3.days.ago new Date() - 3 }
  72. Groovy’s date / time handling 47 import static java.util.Calendar.* import

    groovy.time.* import org.codehaus.groovy.runtime.TimeCategory ! def cal = Calendar.instance cal.set(year: 2010, month: JULY, date: 9) ! assert FRIDAY == cal[DAY_OF_WEEK] ! use (TimeCategory) { 2.years + 3.months + 15.days + 23.minutes + 2.seconds ! 1.week - 1.day new Date() + 6.days ! 3.days.ago new Date() - 3 } Groovy could provide the same for Date / Time
  73. Groovy’s date / time handling 47 import static java.util.Calendar.* import

    groovy.time.* import org.codehaus.groovy.runtime.TimeCategory ! def cal = Calendar.instance cal.set(year: 2010, month: JULY, date: 9) ! assert FRIDAY == cal[DAY_OF_WEEK] ! use (TimeCategory) { 2.years + 3.months + 15.days + 23.minutes + 2.seconds ! 1.week - 1.day new Date() + 6.days ! 3.days.ago new Date() - 3 }
  74. map map map map map reduce reduce reduce reduce reduce

    Map / filter / reduce explained to your 6 year old
  75. Stream 50 persons.stream() .filter( p -> p.getAge() < 18 )

    .map( p -> p.getName().toUpperCase() ) .sorted() .collect(Collectors.joining(", "));
  76. Groovy’s functional style with the GDK methods 51 persons .findAll

    { it.getAge() < 18 } .collect { it.name.toUpperCase() } .sort() .joining(", ")
  77. Groovy using streams too! 52 persons.stream() .filter { it.age <

    18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))
  78. Groovy using streams too! 52 persons.stream() .filter { it.age <

    18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", ")) Leveraging closure to « SAM » type coercion
  79. Groovy using streams too! 52 persons.stream() .filter { it.age <

    18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))
  80. Optional 53 Optional<String> maybeName = Optional.of("Guillaume"); ! String result =

    maybeName.orElse("unknown") ! if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }
  81. Optional 53 Optional<String> maybeName = Optional.of("Guillaume"); ! String result =

    maybeName.orElse("unknown") ! if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); } Wrap something that can be potentially null
  82. Optional 53 Optional<String> maybeName = Optional.of("Guillaume"); ! String result =

    maybeName.orElse("unknown") ! if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }
  83. Optional 53 Optional<String> maybeName = Optional.of("Guillaume"); ! String result =

    maybeName.orElse("unknown") ! if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); } Force handling the null value
  84. Optional 53 Optional<String> maybeName = Optional.of("Guillaume"); ! String result =

    maybeName.orElse("unknown") ! if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }
  85. You know you can customize the truth in Groovy? Just

    implement a custom asBoolean() method!
  86. The law of Groovy Truth 55 Everything that’s null, empty,

    zero-sized, equal to zero is false Otherwise, it’s true!
  87. ?:

  88. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase()
  89. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase() Elvis!
  90. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase() Groovy Truth!
  91. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase() Safe navigation
  92. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase() Interesting discussions on the mailing-list to further enhance usage of Optional from Groovy
  93. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase() Not Yet Implemented
  94. Groovy truth, null handling, Elvis with Optional 57 def maybeName

    = Optional.of("Guillaume") ! def result = maybeName ?: "unknown" ! if (maybeName) { println maybeName.get() } else { println "unknown" } ! maybeName?.toUpperCase()
  95. Call JavaScript from Groovy with JSR-223 59 def manager =

    new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") ! assert engine.eval("{} + []") == 0
  96. Call JavaScript from Groovy with JSR-223 59 def manager =

    new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") ! assert engine.eval("{} + []") == 0 Sane JavaScript logic :-)
  97. GroovyFX 63 import javafx.scene.Scene import static groovyx.javafx.GroovyFX.start ! def chamber

    = ["5 Stelle": 108, "Italia.\nBene commune": 340, "Con Monti per l'Italia": 45, "Berlusconi": 124, "others": 4] ! start { stage(title: 'Italian chamber of Deputies', width: 1024, height: 700, visible: true) { Scene s = scene { tilePane { barChart(barGap: 10, categoryGap: 20, title: "Italy's election in February 2013") { series(name: 'Chamber (seats)', data: ['5 Stelle', 17.5, 'Monti', 7.8, 'Bene commune', 55, 'Berlusconi', 19.9]) series(name: 'Senate (seats)', data: ['5 Stelle', 17.4, 'Monti', 6.1, 'Bene commune', 39.1, 'Berlusconi', 37.1]) } pieChart(data: chamber, title: "Chamber of Deputies") } } s.stylesheets.add("Chart.css") } }
  98. GroovyFX 63 import javafx.scene.Scene import static groovyx.javafx.GroovyFX.start ! def chamber

    = ["5 Stelle": 108, "Italia.\nBene commune": 340, "Con Monti per l'Italia": 45, "Berlusconi": 124, "others": 4] ! start { stage(title: 'Italian chamber of Deputies', width: 1024, height: 700, visible: true) { Scene s = scene { tilePane { barChart(barGap: 10, categoryGap: 20, title: "Italy's election in February 2013") { series(name: 'Chamber (seats)', data: ['5 Stelle', 17.5, 'Monti', 7.8, 'Bene commune', 55, 'Berlusconi', 19.9]) series(name: 'Senate (seats)', data: ['5 Stelle', 17.4, 'Monti', 6.1, 'Bene commune', 39.1, 'Berlusconi', 37.1]) } pieChart(data: chamber, title: "Chamber of Deputies") } } s.stylesheets.add("Chart.css") } } Groovy builder to the rescue!
  99. Android support • You can use Groovy to code Android

    apps! • use Groovy 2.4.0-beta-1+ • prefer @CompileStatic ! • Two great posts to get started: • http://melix.github.io/blog/2014/06/grooid.html • http://melix.github.io/blog/2014/06/grooid2.html 66
  100. What does NYT likes about Groovy on Android? • No

    Java 8, no lambda on Android… 68 Func0 func = new Func0<string>() { @Override public String call() { return "my content"; } }; Async.start(func);
  101. What does NYT likes about Groovy on Android? • No

    Java 8, no lambda on Android… 69 ! ! ! ! ! ! Async.start { "my content" }
  102. What does NYT likes about Groovy on Android? • No

    Java 8, no lambda on Android… 69 ! ! ! ! ! ! Async.start { "my content" } Good bye annonymous inner classes!
  103. What does NYT likes about Groovy on Android? ! •

    Groovy code more concise and more readable ! • but just as type-safe as needed!
 (with @TypeChecked) ! • but just as fast as needed!
 (with @CompileStatic) 70
  104. Grails — web framework 73 @Grab("com.h2database:h2:1.3.173") import grails.persistence.* ! @Entity

    @Resource(uri='/books') class Book { String title } One class, one command, and you’ve got a full REST CRUD application!
  105. Ratpack — web framework 74 @GrabResolver("https://oss.jfrog.org/artifactory/repo") @Grab("org.ratpack-framework:ratpack-groovy:0.9.8") import static org.ratpackframework.groovy.RatpackScript.ratpack

    import static org.ratpackframework.groovy.Template.groovyTemplate ! ratpack { handlers { get { response.send "Welcome!" } ! get("date") { render groovyTemplate("date.html") } ! assets "public" } }
  106. Ratpack — web framework 74 @GrabResolver("https://oss.jfrog.org/artifactory/repo") @Grab("org.ratpack-framework:ratpack-groovy:0.9.8") import static org.ratpackframework.groovy.RatpackScript.ratpack

    import static org.ratpackframework.groovy.Template.groovyTemplate ! ratpack { handlers { get { response.send "Welcome!" } ! get("date") { render groovyTemplate("date.html") } ! assets "public" } } Lightweight Netty-based web application toolkit
  107. @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable

    boolean enabled = true } Griffon — rich desktop applications 75 Model @ArtifactProviderFor(GriffonController) class ConsoleController { def model ! @Inject Evaluator evaluator ! void executeScript() { model.enabled = false def result try { result = evaluator.evaluate(model.scriptSource) } finally { model.enabled = true model.scriptResult = result } } } Controller
  108. @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable

    boolean enabled = true } Griffon — rich desktop applications 75 Model @ArtifactProviderFor(GriffonController) class ConsoleController { def model ! @Inject Evaluator evaluator ! void executeScript() { model.enabled = false def result try { result = evaluator.evaluate(model.scriptSource) } finally { model.enabled = true model.scriptResult = result } } } Controller application(title: application.configuration['application.title'], pack: true, locationByPlatform: true, id: 'mainWindow', iconImage: imageIcon('/griffon-icon-48x48.png').image, iconImages: [imageIcon('/griffon-icon-48x48.png').image, imageIcon('/griffon-icon-32x32.png').image, imageIcon('/griffon-icon-16x16.png').image]) { panel(border: emptyBorder(6)) { borderLayout() scrollPane(constraints: CENTER) { textArea(text: bind(target: model, 'scriptSource'), enabled: bind { model.enabled }, columns: 40, rows: 10) } ! hbox(constraints: SOUTH) { button(executeScriptAction) hstrut(5) label('Result:') hstrut(5) textField(editable: false, text: bind { model.scriptResult }) } } } View
  109. Spock — unit testing & specification 76 @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.*

    ! class MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c ! where: a | b || c 1 | 3 || 3 7 | 4 || 7 0 | 0 || 0 } }
  110. Spock — unit testing & specification 76 @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.*

    ! class MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c ! where: a | b || c 1 | 3 || 3 7 | 4 || 7 0 | 0 || 0 } } Readable & concise expectations
  111. Spock — unit testing & specification 76 @Grab('org.spockframework:spock-core:0.7-groovy-2.0') import spock.lang.*

    ! class MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c ! where: a | b || c 1 | 3 || 3 7 | 4 || 7 0 | 0 || 0 } } Readable & concise expectations Awesome data-driven tests with a wiki-like notation
  112. Geb — browser automation 77 import geb.Browser ! Browser.drive {

    go "http://myapp.com/login" ! assert $("h1").text() == "Please Login" ! $("form.login").with { username = "admin" password = "password" login().click() } ! assert $("h1").text() == 
 "Admin Section" }
  113. Geb — browser automation 77 import geb.Browser ! Browser.drive {

    go "http://myapp.com/login" ! assert $("h1").text() == "Please Login" ! $("form.login").with { username = "admin" password = "password" login().click() } ! assert $("h1").text() == 
 "Admin Section" } Drive your browser
  114. Geb — browser automation 77 import geb.Browser ! Browser.drive {

    go "http://myapp.com/login" ! assert $("h1").text() == "Please Login" ! $("form.login").with { username = "admin" password = "password" login().click() } ! assert $("h1").text() == 
 "Admin Section" } Drive your browser JQuery-like selectors
  115. Geb — browser automation 77 import geb.Browser ! Browser.drive {

    go "http://myapp.com/login" ! assert $("h1").text() == "Please Login" ! $("form.login").with { username = "admin" password = "password" login().click() } ! assert $("h1").text() == 
 "Admin Section" } Drive your browser JQuery-like selectors Fill & submit forms
  116. Gradle — build automation 78 apply plugin: 'java' apply plugin:

    'eclipse' ! sourceCompatibility = 1.5 version = '1.0' jar { manifest { attributes 'Implementation-Title': 'Gradle Quickstart' } } ! repositories { mavenCentral() } ! dependencies { compile ‘commons-collections:commons-collections:3.2’ testCompile 'junit:junit:4.+' } ! uploadArchives { repositories { flatDir { dirs 'repos' } } }
  117. Gradle — build automation 78 apply plugin: 'java' apply plugin:

    'eclipse' ! sourceCompatibility = 1.5 version = '1.0' jar { manifest { attributes 'Implementation-Title': 'Gradle Quickstart' } } ! repositories { mavenCentral() } ! dependencies { compile ‘commons-collections:commons-collections:3.2’ testCompile 'junit:junit:4.+' } ! uploadArchives { repositories { flatDir { dirs 'repos' } } } Powerful and readable DSL for automating your builds and deployments
  118. GPars — concurrency / parallelism / async / … 79

    import static groovyx.gpars.actor.Actors.actor ! def decryptor = actor { loop { react { message -> if (message instanceof String) reply message.reverse() else stop() } } } ! def console = actor { decryptor.send 'lellarap si yvoorG' react { println 'Decrypted message: ${it}' decryptor.send false } } ! [decryptor, console]*.join()
  119. GPars — concurrency / parallelism / async / … 79

    import static groovyx.gpars.actor.Actors.actor ! def decryptor = actor { loop { react { message -> if (message instanceof String) reply message.reverse() else stop() } } } ! def console = actor { decryptor.send 'lellarap si yvoorG' react { println 'Decrypted message: ${it}' decryptor.send false } } ! [decryptor, console]*.join() Actors…
  120. GPars — concurrency / parallelism / async / … 79

    import static groovyx.gpars.actor.Actors.actor ! def decryptor = actor { loop { react { message -> if (message instanceof String) reply message.reverse() else stop() } } } ! def console = actor { decryptor.send 'lellarap si yvoorG' react { println 'Decrypted message: ${it}' decryptor.send false } } ! [decryptor, console]*.join() Actors… But also: Dataflow concurrency, CSP, agents, concurrent collection processing, fork / join, composable async functions, STM
  121. Groovy modules • Ant scripting • JMX • JSON •

    Servlet • Swing • SQL • Templating • Testing • XML 81
  122. Groovy modules • Ant scripting • JMX • JSON •

    Servlet • Swing • SQL • Templating • Testing • XML 82
  123. Ant + XML 83 def writer = new StringWriter() def

    mkp = new MarkupBuilder(writer) ! mkp.html { head { title 'Build notification' } body { p 'Your build was successful' } } ! new AntBuilder().mail(mailhost: 'localhost', messagemimetype: 'text/html', subject: 'Build successful') { ! from address: '[email protected]' to address: '[email protected]' message writer attchments { fileset(dir: 'dist') { include name: '**/logs*.txt' } } }
  124. Ant + XML 83 def writer = new StringWriter() def

    mkp = new MarkupBuilder(writer) ! mkp.html { head { title 'Build notification' } body { p 'Your build was successful' } } ! new AntBuilder().mail(mailhost: 'localhost', messagemimetype: 'text/html', subject: 'Build successful') { ! from address: '[email protected]' to address: '[email protected]' message writer attchments { fileset(dir: 'dist') { include name: '**/logs*.txt' } } } Generate some HTML with the XML support
  125. Ant + XML 83 def writer = new StringWriter() def

    mkp = new MarkupBuilder(writer) ! mkp.html { head { title 'Build notification' } body { p 'Your build was successful' } } ! new AntBuilder().mail(mailhost: 'localhost', messagemimetype: 'text/html', subject: 'Build successful') { ! from address: '[email protected]' to address: '[email protected]' message writer attchments { fileset(dir: 'dist') { include name: '**/logs*.txt' } } } Generate some HTML with the XML support Use the Ant builder and the mail task
  126. Ant + XML 83 def writer = new StringWriter() def

    mkp = new MarkupBuilder(writer) ! mkp.html { head { title 'Build notification' } body { p 'Your build was successful' } } ! new AntBuilder().mail(mailhost: 'localhost', messagemimetype: 'text/html', subject: 'Build successful') { ! from address: '[email protected]' to address: '[email protected]' message writer attchments { fileset(dir: 'dist') { include name: '**/logs*.txt' } } } Generate some HTML with the XML support Use the Ant builder and the mail task Use the Ant’s fileset
  127. JSON support — creating JSON 84 import groovy.json.* ! def

    json = new JsonBuilder() json.person { name 'Guillaume' age 37 daughters 'Marion', 'Erine' address { street '1 Main Street' zip 75001 city 'Paris' } }
  128. JSON support — creating JSON 84 import groovy.json.* ! def

    json = new JsonBuilder() json.person { name 'Guillaume' age 37 daughters 'Marion', 'Erine' address { street '1 Main Street' zip 75001 city 'Paris' } } { "person": { "name": "Guillaume", "age": 37, "daughters": [ "Marion", "Erine" ], "address": { "street": "1 Main Street", "zip": 75001, "city": "Paris" } } }
  129. JSON support — parsing JSON 85 import groovy.json.* ! def

    url = 
 "https://api.github.com/repos/groovy/groovy-core/commits" ! def commits = new JsonSlurper().parseText(url.toURL().text) ! assert commits[0].commit.author.name == 'Cedric Champeau'
  130. JSON support — parsing JSON 85 import groovy.json.* ! def

    url = 
 "https://api.github.com/repos/groovy/groovy-core/commits" ! def commits = new JsonSlurper().parseText(url.toURL().text) ! assert commits[0].commit.author.name == 'Cedric Champeau' The power of a dynamic language!
  131. Template module — new markup template engine • Based on

    the principles of Groovy’s « builders » • and particularly the MarkupBuilder class
 for generating arbitrary XML / HTML payloads ! • Compiled statically for fast template rendering ! • Internationalization aware • provide the desired Locale in the configuration object • usual suffix notation template_fr_FR.tpl ! • Custom base template class • ability to provide reusable methods across your templates 86
  132. Template module — new markup template engine • Based on

    the principles of Groovy’s « builders » • and particularly the MarkupBuilder class
 for generating arbitrary XML / HTML payloads ! • Compiled statically for fast template rendering ! • Internationalization aware • provide the desired Locale in the configuration object • usual suffix notation template_fr_FR.tpl ! • Custom base template class • ability to provide reusable methods across your templates 86 Spring Boot approved
  133. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } }
  134. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } } Your template
  135. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]]
  136. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]] Feed a model into your template
  137. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]] <cars> <car make='Peugeot' name='508'/> <car make='Toyota' name='Prius'/> </cars>
  138. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]] <cars> <car make='Peugeot' name='508'/> <car make='Toyota' name='Prius'/> </cars> Generate the XML output
  139. Markup template engine — the idea 87 cars { cars.each

    { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]] <cars> <car make='Peugeot' name='508'/> <car make='Toyota' name='Prius'/> </cars>
  140. Markup template engine — in action 88 import  groovy.text.markup.*  

    ! def  config  =  new  TemplateConfiguration()   def  engine  =  new  MarkupTemplateEngine(config)   def  tmpl  =  engine.createTemplate('''          p("Hello  ${model.name}")   ''')   def  model  =  [name:  'World']   System.out  <<  tmpl.make(model)
  141. Longer answer: Yes, because… • You can benefit from Java

    8 in Groovy 92 Synergy
 the whole is 
 greater than the sum of the parts
  142. Longer answer: Yes, because… • Groovy goes beyond what Java

    8 offers 93 Beyond
 Groovy always tries to add something to the table
  143. Questions still open: Syntax support for… • lambdas • not

    necessarily,
 (confusing / duplication) ! • method references • enhance method closures • or replace them with method references ! • interface default methods • yes: traits methods aren’t default methods • repeated annotations • yes: not urgent • but less boilerplate is good ! • annotations on type • yes: opens up new possibilities for targets of local AST transformation ! • interface static methods • yes: for Java compatibility 94
  144. Further possible API enhancements • Make Optional Groovy-friendly • with

    regards to Groovy Truth • accessing the wrapped value ! • More Groovy methods for… • NIO • Streams • Date / time ! • Operator overloading for Date / time • for arithmetics on instants and durations 95
  145. Further possible API enhancements • Make Optional Groovy-friendly • with

    regards to Groovy Truth • accessing the wrapped value ! • More Groovy methods for… • NIO • Streams • Date / time ! • Operator overloading for Date / time • for arithmetics on instants and durations 95 Community feedback & contributions welcome!
  146. Image credits • Question mark • http://www.mynamesnotmommy.com/wp-content/uploads/2013/05/question-mark.png • Get out!

    • http://static.comicvine.com/uploads/original/11/117995/3772037-0075368930-27616.jpg • Yes • http://soloprpro.com/wp-content/uploads/2013/08/yes.jpg • Synergy • http://www.wildblueberries.com/wp-content/uploads/blogger/_YhH8fDK5-kU/S_5kYWwgAbI/AAAAAAAAAKU/JQ_-ISfT9KY/s1600/ teamwork.jpg • Buzz Lightyear • http://www.disneypictures.net/data/media/202/Buzz_Lightyear_hd.jpg • Start wars spaceship • http://swc.fs2downloads.com/media/screenshots/Support_Trans/Shuttle/lambda003.jpg • Lambda character • http://lambda.ninjackaton.ninja-squad.com/images/lambda.png • Man clock • http://3.bp.blogspot.com/-7hLQ9tnmA84/TuTIoLRLMTI/AAAAAAAABWM/g7ahyLCRjJQ/s1600/Harold+Lloyd+Safety+Last.jpg • Stream • http://wallpaperswide.com/forest_stream-wallpapers.html • Nashorn (rhino) • http://2010sdafrika.files.wordpress.com/2012/07/hi_257587-nashorn-c-naturepl-com-mark-carwardine-wwf-canon.jpg 98
  147. Image credits • Brain • http://www.semel.ucla.edu/sites/all/files/users/user-412/dreamstime_xxl_17754591%20(2).jpg • Many thanks •

    http://www.trys.ie/wp-content/uploads/2013/06/many-thanks.jpg • Swing • http://makemesomethingspecial.co.uk/wp-content/uploads/2012/10/Solid-Oak-Handmade-Spliced-Swing-With-Personalised- Engraving-10867.jpg • Disclaimer • http://3.bp.blogspot.com/-RGnBpjXTCQA/Tj2h_JsLigI/AAAAAAAABbg/AB5ZZYzuE5w/s1600/disclaimer.jpg • Hammer / justice / truth • http://www.bombayrealty.in/images/disclaimer.jpg • Law • http://www.permanentmakeupbymv.com/wp-content/uploads/2014/07/law-2.jpg • Glasses / readable • http://a.fastcompany.net/multisite_files/coexist/imagecache/1280/poster/2013/02/1681393-poster-1280-responsive-eye-chart.jpg • We need you • http://www.bostonbreakerssoccer.com/imgs/ABOUT/volopps/we%20need%20you.JPG • Golden Gate • http://www.airpano.com/files/San-Francisco-Golden-Gate-USA/sf_golden_gate.jpg 99
  148. Image credits • Turtles • http://33.media.tumblr.com/77095e3a37acb2272133c405b1f7ba54/tumblr_myfydjNgXJ1s20kxvo1_1280.jpg • Annotations • http://3.bp.blogspot.com/-f94n9BHko_s/T35ELs7nYvI/AAAAAAAAAKg/qe06LRPH9U4/s1600/IMG_1721.JPG

    • Builders • http://detroittraining.com/wp-content/uploads/Construction-Women2.jpg • Sandwich ingredients • http://www.fromages-de-terroirs.com/IMG/MEULE_DETOUREE_72_DPI_-2.jpg • http://eboutique-hebergement.orange-business.com/WebRoot/Orange/Shops/Madeinalsace/4B02/6320/943E/DB4F/DDBF/ 0A0A/33E8/4BC8/iStock_000008775559XSmall.jpg • http://www.cmonprimeur.fr/images/25834-vegetable-pictures%5B1%5D.jpg • http://1.bp.blogspot.com/-27UoqYeYtY4/T4PAr4zGSnI/AAAAAAAAA3s/lleE-NOh0LE/s1600/IMG_1528.JPG • http://www.growingpatch.com/wp-content/uploads/2014/05/tomato-9.jpg • http://vitaminsandhealthsupplements.com/wp-content/uploads/2013/08/fresh-sliced-tomato.jpg • http://2.bp.blogspot.com/-3pPmRhBHv9s/T3D-EtLlN1I/AAAAAAAAAgg/Y5oTM84nGb8/s1600/cochon+2.jpg • http://www.salamarket.fr/wp-content/uploads/steak-hach%C3%A9.jpg • http://www.quinzanisbakery.com/images/bread-vienna.jpg • http://www.saucissonvaudois.qc.ca/images/produits/Jambon_blanc.jpg • http://www.audion.com/system/public/categories/125/images/bread-sandwich.jpg 100