$30 off During Our Annual Pro Sale. View Details »

Groovy in the light of Java 8 -- Devoxx 2014

Groovy in the light of Java 8 -- Devoxx 2014

With Java 8 out the door, Java developers can, at last, benefit from the long-awaited lambdas, to taste the newly-found functional flavor of the language. Streams are there to work more easily and efficiently with heaps of data. Those things are not new to developers acquainted with Groovy. But what is left to Groovy to make it attractive beyond all the aspects Java has caught up with Groovy? In this session, Guillaume Laforge, Groovy project lead, will show you how Groovy is still relevant in the JVM landscape, how similar or different both Java and Groovy can be, how Groovy further improves the developer experience on top of JDK 8, and what Groovy offers beyond Java!

Guillaume Laforge

November 14, 2014
Tweet

More Decks by Guillaume Laforge

Other Decks in Programming

Transcript

  1. @glaforge #devoxx #groovylang Groovy in the light of Java 8

    Guillaume Laforge Groovy project manager
  2. @glaforge #devoxx #groovylang 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
  3. @glaforge #devoxx #groovylang What about redundancy? • Closures • Traits

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

    the details :-) We want to understand the implications with regards to Groovy
  5. @glaforge #devoxx #groovylang 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
  6. @glaforge #devoxx #groovylang 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
  7. @glaforge #devoxx #groovylang 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. @glaforge #devoxx #groovylang 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. @glaforge #devoxx #groovylang Lambda expressions 15 double highestScore = students

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

    .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();
  11. @glaforge #devoxx #groovylang 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. @glaforge #devoxx #groovylang Lambda expressions 16 double highestScore = students

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

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

    .filter(Student s -> s.getGradYear() == 2011) .map(Student s -> s.getScore()) .max();
  15. @glaforge #devoxx #groovylang Lambda expressions 17 double highestScore = students

    .findAll { it.gradYear == 2011 } .collect { it.score} .max()
  16. @glaforge #devoxx #groovylang Lambda expressions 17 double highestScore = students

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

    .findAll { it.gradYear == 2011 } .collect { it.score} .max() Drawback: intermediary data structures Unless you use iterator variants
  18. @glaforge #devoxx #groovylang Lambda expressions 17 double highestScore = students

    .findAll { it.gradYear == 2011 } .collect { it.score} .max()
  19. @glaforge #devoxx #groovylang Lambda expressions 18 double highestScore = students

    .filter { Student s -> s.gradYear == 2011 } .map { Student s -> s.getScore() } .max()
  20. @glaforge #devoxx #groovylang Lambda expressions 18 double highestScore = students

    .filter { Student s -> s.gradYear == 2011 } .map { Student s -> s.getScore() } .max() Same coercion to Predicate but works for abstract classes too
  21. @glaforge #devoxx #groovylang Lambda expressions 18 double highestScore = students

    .filter { Student s -> s.gradYear == 2011 } .map { Student s -> s.getScore() } .max()
  22. @glaforge #devoxx #groovylang The various lambda syntaxes 19 String name

    -> name.length() (int left, int right) -> left + right (String left, String sep, String right) -> { System.out.println(left + sep + right) }
  23. @glaforge #devoxx #groovylang The various lambda syntaxes 19 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
  24. @glaforge #devoxx #groovylang The various lambda syntaxes 19 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
  25. @glaforge #devoxx #groovylang The various lambda syntaxes 19 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
  26. @glaforge #devoxx #groovylang The various lambda syntaxes 19 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
  27. @glaforge #devoxx #groovylang Closures vs lambdas 20 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));
  28. @glaforge #devoxx #groovylang Closures vs lambdas 20 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 }
  29. @glaforge #devoxx #groovylang Closures vs lambdas 20 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
  30. @glaforge #devoxx #groovylang Closures vs lambdas 20 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)
  31. @glaforge #devoxx #groovylang Closures vs lambdas 20 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 }
  32. @glaforge #devoxx #groovylang Beyond: Closure default parameters 21 def mult

    = { int a, int b = 10 -> a * b } assert mult(2, 3) == 6 assert mult(5) == 50
  33. @glaforge #devoxx #groovylang Beyond: Closure default parameters 21 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
  34. @glaforge #devoxx #groovylang Beyond: Duck typing polymorphism 22 def adder

    = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY'
  35. @glaforge #devoxx #groovylang Beyond: Duck typing polymorphism 22 def adder

    = { a, b -> a + b } assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY' Works both for numbers and for strings
  36. @glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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"); }); });
  37. @glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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
  38. @glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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
  39. @glaforge #devoxx #groovylang Lambda-based builders uglier and less 24 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
  40. @glaforge #devoxx #groovylang Neater Groovy builder! 25 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" } } }
  41. @glaforge #devoxx #groovylang Neater Groovy builder! 25 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" } } }
  42. @glaforge #devoxx #groovylang Closure and method memoization 29 def fib2

    = { long n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize()
  43. @glaforge #devoxx #groovylang Closure and method memoization 29 def fib2

    = { long n -> if (n < 2) 1 else call(n - 1) + call(n - 2) }.memoize() Closures: memoize()
  44. @glaforge #devoxx #groovylang Closure and method memoization 29 @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()
  45. @glaforge #devoxx #groovylang Closure and method memoization 29 @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
  46. @glaforge #devoxx #groovylang Closure and method tail recursion 31 def

    fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline()
  47. @glaforge #devoxx #groovylang Closure and method tail recursion 31 def

    fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline() Closures: Tail recursion with trampoline()
  48. @glaforge #devoxx #groovylang Closure and method tail recursion 31 @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()
  49. @glaforge #devoxx #groovylang Closure and method tail recursion 31 @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
  50. @glaforge #devoxx #groovylang Method references — 3 main cases •

    Three main cases: 33 instance::instanceMethod SomeClass::staticMethod SomeClass::instanceMethod
  51. @glaforge #devoxx #groovylang Method references — 3 main cases •

    Three main cases: 33 instance::instanceMethod SomeClass::staticMethod SomeClass::instanceMethod Not covered by Groovy method closures yet!
  52. @glaforge #devoxx #groovylang Static methods in interfaces • You can

    put static utility methods in interfaces, 
 instead of in companion classes (like « Collections ») 35 public interface Stream<T> { // ... static <T> Stream<T> empty() { return new Stream<T> { ... } } }
  53. @glaforge #devoxx #groovylang Default methods in interfaces • Define default

    behavior • possibly to enrich existing interfaces 36 public interface Stream<T> { // ... default Builder<T> add(T t) { ... } }
  54. @glaforge #devoxx #groovylang 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 37
  55. @glaforge #devoxx #groovylang Simple trait 38 trait FlyingAbility { String

    fly() { "I'm flying!" } } class Bird implements FlyingAbility {} def b = new Bird() assert b.fly() == "I'm flying!"
  56. @glaforge #devoxx #groovylang Trait with state 39 trait Named {

    String name } class Bird implements Named {} def b = new Bird(name: 'Colibri') assert b.name == 'Colibri'
  57. @glaforge #devoxx #groovylang Multiple inheritance 40 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'
  58. @glaforge #devoxx #groovylang Repeating annotations 42 @Schedule(dayOfMonth = "last") @Schedule(dayOfWeek

    = "Fri", hour = 23) public void doPeriodicCleanup() { ... } @Schedule annotation repeated twice
  59. @glaforge #devoxx #groovylang Repeating annotations 42 @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; }
  60. @glaforge #devoxx #groovylang Repeating annotations 42 @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
  61. @glaforge #devoxx #groovylang Repeating annotations 42 @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(); }
  62. @glaforge #devoxx #groovylang Repeating annotations 42 @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
  63. @glaforge #devoxx #groovylang Repeating annotations 42 @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(); }
  64. @glaforge #devoxx #groovylang Repeating annotations 42 @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
  65. @glaforge #devoxx #groovylang Repeating annotations 42 @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(); }
  66. @glaforge #devoxx #groovylang Annotations on types • Everywhere you can

    put a type, you can put an annotation 43 @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> {...}
  67. @glaforge #devoxx #groovylang Annotations on types • Everywhere you can

    put a type, you can put an annotation 43 @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
  68. @glaforge #devoxx #groovylang Annotations on types • Everywhere you can

    put a type, you can put an annotation 43 @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?
  69. @glaforge #devoxx #groovylang Annotations on types • Everywhere you can

    put a type, you can put an annotation 43 @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> {...}
  70. @glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 @Service @Transactional class

    MyTransactionalService {} import groovy.transform.AnnotationCollector @Service @Transactional @AnnotationCollector public @interface TransactionalService {}
  71. @glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 import groovy.transform.AnnotationCollector @Service

    @Transactional @AnnotationCollector public @interface TransactionalService {} @TransactionalService class MyTransactionalService {}
  72. @glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 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 »
  73. @glaforge #devoxx #groovylang Groovy compile-time meta-annotations 44 import groovy.transform.AnnotationCollector @Service

    @Transactional @AnnotationCollector public @interface TransactionalService {} @TransactionalService class MyTransactionalService {}
  74. @glaforge #devoxx #groovylang Date / Time API 47 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));
  75. @glaforge #devoxx #groovylang Date / Time API 47 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?
  76. @glaforge #devoxx #groovylang Date / Time API 47 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));
  77. @glaforge #devoxx #groovylang Groovy’s date / time handling 48 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 }
  78. @glaforge #devoxx #groovylang Groovy’s date / time handling 48 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
  79. @glaforge #devoxx #groovylang Groovy’s date / time handling 48 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 }
  80. map map map map map reduce reduce reduce reduce reduce

    Map / filter / reduce explained to your 6 year old
  81. @glaforge #devoxx #groovylang Stream 51 persons.stream() .filter( p -> p.getAge()

    < 18 ) .map( p -> p.getName().toUpperCase() ) .sorted() .collect(Collectors.joining(", "));
  82. @glaforge #devoxx #groovylang Groovy’s functional style with GDK methods 52

    persons .findAll { it.getAge() < 18 } .collect { it.name.toUpperCase() } .sort() .join(", ")
  83. @glaforge #devoxx #groovylang Groovy using streams too! 53 persons.stream() .filter

    { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))
  84. @glaforge #devoxx #groovylang Groovy using streams too! 53 persons.stream() .filter

    { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", ")) Leveraging closure to « SAM » type coercion
  85. @glaforge #devoxx #groovylang Groovy using streams too! 53 persons.stream() .filter

    { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))
  86. @glaforge #devoxx #groovylang Optional 54 Optional<String> maybeName = Optional.of("Guillaume"); String

    result = maybeName.orElse("unknown") if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }
  87. @glaforge #devoxx #groovylang Optional 54 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
  88. @glaforge #devoxx #groovylang Optional 54 Optional<String> maybeName = Optional.of("Guillaume"); String

    result = maybeName.orElse("unknown") if (maybeName.ifPresent()) { System.out.println(maybeName.get()); } else { System.out.println("unknown"); }
  89. @glaforge #devoxx #groovylang Optional 54 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
  90. @glaforge #devoxx #groovylang Optional 54 Optional<String> maybeName = Optional.of("Guillaume"); String

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

    implement a custom asBoolean() method!
  92. @glaforge #devoxx #groovylang The law of Groovy Truth 56 Everything

    that’s null, empty, zero-sized, equal to zero is false
  93. @glaforge #devoxx #groovylang The law of Groovy Truth 56 Everything

    that’s null, empty, zero-sized, equal to zero is false Otherwise, it’s true!
  94. ?:

  95. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase()
  96. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Elvis!
  97. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Groovy Truth!
  98. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Safe navigation
  99. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 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
  100. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase() Not Yet Implemented
  101. @glaforge #devoxx #groovylang Groovy truth, null handling, Elvis & Optional

    58 def maybeName = Optional.of("Guillaume") def result = maybeName ?: "unknown" if (maybeName) { println maybeName.get() } else { println "unknown" } maybeName?.toUpperCase()
  102. @glaforge #devoxx #groovylang Call JavaScript from Groovy with JSR-223 60

    def manager = new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") assert engine.eval("{} + []") == 0
  103. @glaforge #devoxx #groovylang Call JavaScript from Groovy with JSR-223 60

    def manager = new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") assert engine.eval("{} + []") == 0 Sane JavaScript logic :-)
  104. @glaforge #devoxx #groovylang GrooScript — http://grooscript.org/ 61 JS Gradle &

    Grails plugins available Examples available with Ratpack, Node.JS…
  105. @glaforge #devoxx #groovylang GroovyFX 64 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") } }
  106. @glaforge #devoxx #groovylang GroovyFX 64 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!
  107. @glaforge #devoxx #groovylang 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 67
  108. @glaforge #devoxx #groovylang What does NYT likes about Groovy on

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

    Android? • No Java 8, no lambda on Android… 70 Async.start { "my content" }
  110. @glaforge #devoxx #groovylang What does NYT likes about Groovy on

    Android? • No Java 8, no lambda on Android… 70 Async.start { "my content" } Good bye annonymous inner classes!
  111. @glaforge #devoxx #groovylang 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) 71
  112. @glaforge #devoxx #groovylang Grails — web framework 74 @Grab("com.h2database:h2:1.3.173") import

    grails.persistence.* @Entity @Resource(uri='/books') class Book { String title }
  113. @glaforge #devoxx #groovylang Grails — web framework 74 @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!
  114. @glaforge #devoxx #groovylang Ratpack — web framework 75 @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" } }
  115. @glaforge #devoxx #groovylang Ratpack — web framework 75 @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
  116. @glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable

    Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76
  117. @glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable

    Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76 Model
  118. @glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable

    Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76 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
  119. @glaforge #devoxx #groovylang @ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable

    Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 76 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
  120. @glaforge #devoxx #groovylang Spock — unit testing & specification 77

    @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 } }
  121. @glaforge #devoxx #groovylang Spock — unit testing & specification 77

    @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
  122. @glaforge #devoxx #groovylang Spock — unit testing & specification 77

    @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
  123. @glaforge #devoxx #groovylang Geb — browser automation 78 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" }
  124. @glaforge #devoxx #groovylang Geb — browser automation 78 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
  125. @glaforge #devoxx #groovylang Geb — browser automation 78 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
  126. @glaforge #devoxx #groovylang Geb — browser automation 78 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
  127. @glaforge #devoxx #groovylang Gradle — build automation 79 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' } } }
  128. @glaforge #devoxx #groovylang Gradle — build automation 79 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
  129. @glaforge #devoxx #groovylang GPars: concurrency / parallelism / async /

    … 80 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()
  130. @glaforge #devoxx #groovylang GPars: concurrency / parallelism / async /

    … 80 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…
  131. @glaforge #devoxx #groovylang GPars: concurrency / parallelism / async /

    … 80 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
  132. @glaforge #devoxx #groovylang Groovy modules • Ant scripting • JMX

    • JSON • Servlet • Swing • SQL • Templating • Testing • XML 82
  133. @glaforge #devoxx #groovylang Groovy modules • Ant scripting • JMX

    • JSON • Servlet • Swing • SQL • Templating • Testing • XML 83
  134. @glaforge #devoxx #groovylang Ant + XML 84 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' } } }
  135. @glaforge #devoxx #groovylang Ant + XML 84 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
  136. @glaforge #devoxx #groovylang Ant + XML 84 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
  137. @glaforge #devoxx #groovylang Ant + XML 84 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
  138. @glaforge #devoxx #groovylang JSON support — creating JSON 85 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' } }
  139. @glaforge #devoxx #groovylang JSON support — creating JSON 85 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" } } }
  140. @glaforge #devoxx #groovylang JSON support — parsing JSON 86 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'
  141. @glaforge #devoxx #groovylang JSON support — parsing JSON 86 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!
  142. @glaforge #devoxx #groovylang 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 87
  143. @glaforge #devoxx #groovylang 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 87 Spring Boot approved
  144. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    cars { cars.each { car(make: it.make, name: it.name) } }
  145. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    cars { cars.each { car(make: it.make, name: it.name) } } Your template
  146. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    cars { cars.each { car(make: it.make, name: it.name) } } model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]]
  147. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    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
  148. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    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>
  149. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    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
  150. @glaforge #devoxx #groovylang Markup template engine — the idea 88

    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>
  151. @glaforge #devoxx #groovylang Markup template engine — in action 89

    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)
  152. @glaforge #devoxx #groovylang Back to our original question… Do we

    still need Groovy now that we have Java 8? 91
  153. @glaforge #devoxx #groovylang Longer answer: Yes, because… • You can

    benefit from Java 8 in Groovy 93 Synergy
 the whole is 
 greater than the sum of the parts
  154. @glaforge #devoxx #groovylang Longer answer: Yes, because… • Groovy goes

    beyond what Java 8 offers 94 Beyond
 Groovy always tries to add something to the table
  155. @glaforge #devoxx #groovylang 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 • repeating 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 95
  156. @glaforge #devoxx #groovylang 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 96
  157. @glaforge #devoxx #groovylang 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 96 Community feedback & contributions welcome!
  158. @glaforge #devoxx #groovylang Image credits • Antwerp • http://www.visitflanders.in/binaries/IMG_7895.jpg, http://www.semindex.be/upload/SemIndex/images/Accommodation/23/4_zaal6_original.jpg

    • Antwerp central station • http://4.bp.blogspot.com/_4dEsCVlFCgA/S7horBAdM5I/AAAAAAAAALU/eXOhxk2ou-8/s1600/Antwerp+Station.jpg • 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 • 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 99
  159. @glaforge #devoxx #groovylang Image credits • 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 100
  160. @glaforge #devoxx #groovylang Image credits • 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 • 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 101
  161. @glaforge #devoxx #groovylang Image credits • 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 102