Slide 1

Slide 1 text

Groovy in the light of Java 8 Guillaume Laforge Groovy project lead Pivotal @glaforge

Slide 2

Slide 2 text

Stay up-to-date Groovy Weekly Newsletter (Every Tuesday) http://beta.groovy-lang.org/groovy-weekly.html 2

Slide 3

Slide 3 text

@glaforge — Groovy in the light of Java 8 Goal of this talk

Slide 4

Slide 4 text

A recurring question… Do we still need Groovy now that we have Java 8? 4

Slide 5

Slide 5 text

To those who said no… 5

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

What about redundancy? ! ! ! ! ! • Closures • Traits • Truth & null handling • Functional with collections • Method closures ! ! ! ! ! ! • Lambdas • Default methods • Optional • Stream API • Method references 7

Slide 8

Slide 8 text

@glaforge — Groovy in the light of Java 8 What’s new in Java 8?

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

This is not a Java 8 crash courses with all the details :-)

Slide 11

Slide 11 text

This is not a Java 8 crash courses with all the details :-) We want to understand the implications with regards to Groovy

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

@glaforge — Groovy in the light of Java 8 Support the new Java 8 language features New Java 8 syntax

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Lambda expressions 17 double highestScore = students .findAll { it.gradYear == 2011 } .collect { it.score} .max()

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Lambda expressions 17 double highestScore = students .findAll { it.gradYear == 2011 } .collect { it.score} .max()

Slide 30

Slide 30 text

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) }

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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));

Slide 36

Slide 36 text

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 }

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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)

Slide 39

Slide 39 text

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 }

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

Builders

Slide 45

Slide 45 text

Builders What would Java lambda builders look like?

Slide 46

Slide 46 text

Builders What would Java lambda builders look like? Aren’t Groovy builders more powerful?

Slide 47

Slide 47 text

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"); }); });

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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" } } }

Slide 52

Slide 52 text

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" } } }

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

Aren’t Groovy builders more readable and lean?

Slide 55

Slide 55 text

To those who said no… 26

Slide 56

Slide 56 text

Memoization

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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()

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Tail recursion

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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()

Slide 65

Slide 65 text

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()

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

Method references 31 button.setOnAction(event -> System.out.println(event));

Slide 68

Slide 68 text

Method references 31 button.setOnAction(event -> System.out.println(event)); button.setOnAction(System.out::println);

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

Method references — 3 main cases • Three main cases: 32 instance::instanceMethod ! SomeClass::staticMethod ! SomeClass::instanceMethod Not covered by Groovy method closures yet!

Slide 71

Slide 71 text

Groovy’s method closure 33 instance.&instanceMethod ! SomeClass.&staticMethod ! SomeClass.&instanceMethod

Slide 72

Slide 72 text

Groovy’s method closure 33 instance.&instanceMethod ! SomeClass.&staticMethod ! SomeClass.&instanceMethod Choices: Adopt :: Deprecate .& Enhance .&

Slide 73

Slide 73 text

Static methods in interfaces • You can put static utility methods in interfaces, 
 instead of in companion classes (like « Collections ») 34 public interface Stream { // ... static Stream empty() { return new Stream { ... } } }

Slide 74

Slide 74 text

Default methods in interfaces • Define default behavior • possibly to enrich existing interfaces 35 public interface Stream { // ... default Builder add(T t) { ... } }

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

Simple trait 37 trait FlyingAbility { String fly() { "I'm flying!" } } ! class Bird implements FlyingAbility {} def b = new Bird() ! assert b.fly() == "I'm flying!"

Slide 77

Slide 77 text

Trait with state 38 trait Named { String name } ! class Bird implements Named {} def b = new Bird(name: 'Colibri') ! assert b.name == 'Colibri'

Slide 78

Slide 78 text

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'

Slide 79

Slide 79 text

Annotations on types Repeating annotations

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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; }

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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(); }

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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(); }

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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(); }

Slide 89

Slide 89 text

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 implements @Readonly List<@Readonly T> {...}

Slide 90

Slide 90 text

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 implements @Readonly List<@Readonly T> {...} Not yet supported

Slide 91

Slide 91 text

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 implements @Readonly List<@Readonly T> {...} Imagine the potential for targets for local AST transformations?

Slide 92

Slide 92 text

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 implements @Readonly List<@Readonly T> {...}

Slide 93

Slide 93 text

Groovy compile-time meta-annotations 43 @Service @Transactional class MyTransactionalService {}

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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 »

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

@glaforge — Groovy in the light of Java 8 New Java 8 APIs

Slide 99

Slide 99 text

Date and Time API

Slide 100

Slide 100 text

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));

Slide 101

Slide 101 text

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?

Slide 102

Slide 102 text

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));

Slide 103

Slide 103 text

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 }

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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 }

Slide 106

Slide 106 text

Stream API

Slide 107

Slide 107 text

map map map map map reduce reduce reduce reduce reduce

Slide 108

Slide 108 text

map map map map map reduce reduce reduce reduce reduce Map / filter / reduce explained to your 6 year old

Slide 109

Slide 109 text

map map map map map reduce reduce reduce reduce reduce

Slide 110

Slide 110 text

Stream 50 persons.stream() .filter( p -> p.getAge() < 18 ) .map( p -> p.getName().toUpperCase() ) .sorted() .collect(Collectors.joining(", "));

Slide 111

Slide 111 text

Groovy’s functional style with the GDK methods 51 persons .findAll { it.getAge() < 18 } .collect { it.name.toUpperCase() } .sort() .joining(", ")

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

Optional 53 Optional 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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

Optional 53 Optional 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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

No content

Slide 121

Slide 121 text

You know you can customize the truth in Groovy?

Slide 122

Slide 122 text

You know you can customize the truth in Groovy? Just implement a custom asBoolean() method!

Slide 123

Slide 123 text

The law of Groovy Truth 55

Slide 124

Slide 124 text

The law of Groovy Truth 55 Everything that’s null, empty, zero-sized, equal to zero is false

Slide 125

Slide 125 text

The law of Groovy Truth 55 Everything that’s null, empty, zero-sized, equal to zero is false Otherwise, it’s true!

Slide 126

Slide 126 text

?:

Slide 127

Slide 127 text

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()

Slide 128

Slide 128 text

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!

Slide 129

Slide 129 text

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!

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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()

Slide 134

Slide 134 text

Nashorn

Slide 135

Slide 135 text

Nashorn Speak German?

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

GrooScript — http://grooscript.org/ 60 JS

Slide 139

Slide 139 text

GrooScript — http://grooscript.org/ 60 JS Gradle & Grails plugins available Examples available with Ratpack, Node.JS…

Slide 140

Slide 140 text

Turtles all the way down!

Slide 141

Slide 141 text

Turtles all the way down! Full Groovy!

Slide 142

Slide 142 text

Turtles all the way down! Full Groovy! Back to front

Slide 143

Slide 143 text

Turtles all the way down! Full Groovy! Back to front Front to back

Slide 144

Slide 144 text

JavaFx… ! ! …the new Swing

Slide 145

Slide 145 text

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") } }

Slide 146

Slide 146 text

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!

Slide 147

Slide 147 text

@glaforge — Groovy in the light of Java 8 Beyond Java

Slide 148

Slide 148 text

@glaforge — Groovy in the light of Java 8 Android

Slide 149

Slide 149 text

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

Slide 150

Slide 150 text

New York Times — Getting Groovy with Android 67

Slide 151

Slide 151 text

New York Times — Getting Groovy with Android 67 http://bit.ly/nyt-groovy

Slide 152

Slide 152 text

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

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

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!

Slide 155

Slide 155 text

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

Slide 156

Slide 156 text

Android support 71

Slide 157

Slide 157 text

Android support 71 Source code available: https://github.com/melix/gr8confagenda

Slide 158

Slide 158 text

@glaforge — Groovy in the light of Java 8 A rich Groovy ecosystem

Slide 159

Slide 159 text

Grails — web framework 73 @Grab("com.h2database:h2:1.3.173") import grails.persistence.* ! @Entity @Resource(uri='/books') class Book { String title }

Slide 160

Slide 160 text

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!

Slide 161

Slide 161 text

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" } }

Slide 162

Slide 162 text

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

Slide 163

Slide 163 text

@ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 75

Slide 164

Slide 164 text

@ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true } Griffon — rich desktop applications 75 Model

Slide 165

Slide 165 text

@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

Slide 166

Slide 166 text

@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

Slide 167

Slide 167 text

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 } }

Slide 168

Slide 168 text

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

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

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" }

Slide 171

Slide 171 text

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

Slide 172

Slide 172 text

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

Slide 173

Slide 173 text

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

Slide 174

Slide 174 text

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' } } }

Slide 175

Slide 175 text

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

Slide 176

Slide 176 text

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()

Slide 177

Slide 177 text

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…

Slide 178

Slide 178 text

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

Slide 179

Slide 179 text

@glaforge — Groovy in the light of Java 8 Groovy modules

Slide 180

Slide 180 text

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

Slide 181

Slide 181 text

Groovy modules • Ant scripting • JMX • JSON • Servlet • Swing • SQL • Templating • Testing • XML 82

Slide 182

Slide 182 text

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' } } }

Slide 183

Slide 183 text

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

Slide 184

Slide 184 text

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

Slide 185

Slide 185 text

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

Slide 186

Slide 186 text

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' } }

Slide 187

Slide 187 text

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" } } }

Slide 188

Slide 188 text

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'

Slide 189

Slide 189 text

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!

Slide 190

Slide 190 text

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

Slide 191

Slide 191 text

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

Slide 192

Slide 192 text

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

Slide 193

Slide 193 text

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

Slide 194

Slide 194 text

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’) ]]

Slide 195

Slide 195 text

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

Slide 196

Slide 196 text

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’) ]]

Slide 197

Slide 197 text

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’) ]] Generate the XML output

Slide 198

Slide 198 text

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’) ]]

Slide 199

Slide 199 text

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)

Slide 200

Slide 200 text

@glaforge — Groovy in the light of Java 8 Summary

Slide 201

Slide 201 text

Back to our original question… Do we still need Groovy now that we have Java 8? 90

Slide 202

Slide 202 text

No content

Slide 203

Slide 203 text

Longer answer: Yes, because… • You can benefit from Java 8 in Groovy 92 Synergy
 the whole is 
 greater than the sum of the parts

Slide 204

Slide 204 text

Longer answer: Yes, because… • Groovy goes beyond what Java 8 offers 93 Beyond
 Groovy always tries to add something to the table

Slide 205

Slide 205 text

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

Slide 206

Slide 206 text

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

Slide 207

Slide 207 text

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!

Slide 208

Slide 208 text

@glaforge — Groovy in the light of Java 8 Q & A

Slide 209

Slide 209 text

No content

Slide 210

Slide 210 text

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

Slide 211

Slide 211 text

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

Slide 212

Slide 212 text

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