groovy, in the light of java 8

245
© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission. Groovy, in the light of Java 8 Guillaume Laforge — Groovy project lead / Pivotal @glaforge

Upload: spring-io

Post on 02-Jul-2015

1.064 views

Category:

Software


3 download

DESCRIPTION

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?

TRANSCRIPT

Page 1: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Groovy, in the light of Java 8Guillaume Laforge — Groovy project lead / Pivotal

@glaforge

Page 2: Groovy, in the light of Java 8

Stay up-to-date

Groovy Weekly Newsletter (Every Tuesday) http://beta.groovy-lang.org/groovy-weekly.html

2

Page 3: Groovy, in the light of Java 8

Stay up-to-date

Google+ Groovy Page https://google.com/+groovy

3

Page 4: Groovy, in the light of Java 8

Stay up-to-date

Google+ Groovy Community http://bit.ly/g-community

4

Page 5: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Goal of this talk

Page 6: Groovy, in the light of Java 8

A recurring question…

Do we still need Groovy now that we

have Java 8?

6

Page 7: Groovy, in the light of Java 8

To those who said no…

7

Page 8: Groovy, in the light of Java 8

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?

8

Page 9: Groovy, in the light of Java 8

What about redundancy?

!

!

!

!

!

• Closures • Traits • Truth & null handling • Functional with collections • Method closures

!

!

!

!

!

!

!

• Lambdas • Default methods • Optional • Stream API • Method references

9

Page 10: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Agenda

Page 11: Groovy, in the light of Java 8

What we’re going to talk about

• What’s new in Java 8 • new syntax constructs • new APIs !

• Similar concepts in Groovy • and how they compare or complement !

• What Groovy offers in addition • beyond Java, Groovy adds its own twist!

11

Page 12: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

What’s new in Java 8?

Page 13: Groovy, in the light of Java 8
Page 14: Groovy, in the light of Java 8

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

Page 15: Groovy, in the light of Java 8

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

We want to understand the implications with regards to Groovy

Page 16: Groovy, in the light of Java 8

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

14

Page 17: Groovy, in the light of Java 8

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

14

Great concise resource with the whole list:http://bit.ly/new-in-java-8

Page 18: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Support the new Java 8

language features

New Java 8 syntax

Page 19: Groovy, in the light of Java 8

New Java 8 syntax constructs

• Lambda expressions • Method references • Static & default methods in interfaces • Repeating annotations • Annotations on types • Improved type inference • Method parameter reflection

16

Page 20: Groovy, in the light of Java 8

New Java 8 syntax constructs

• Lambda expressions • Method references • Static & default methods in interfaces • Repeating annotations • Annotations on types • Improved type inference • Method parameter reflection

17

Page 21: Groovy, in the light of Java 8
Page 22: Groovy, in the light of Java 8
Page 23: Groovy, in the light of Java 8
Page 24: Groovy, in the light of Java 8

Lambda expressions

19

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

Page 25: Groovy, in the light of Java 8

Lambda expressions

20

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

Page 26: Groovy, in the light of Java 8

Lambda expressions

20

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

Coercion into a Predicate « functional interface »

Page 27: Groovy, in the light of Java 8

Lambda expressions

20

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

There’s no function type!

Page 28: Groovy, in the light of Java 8

Lambda expressions

20

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

Pipeline being built Single pass!

Page 29: Groovy, in the light of Java 8

Lambda expressions

20

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

Page 30: Groovy, in the light of Java 8

Lambda expressions

21

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

Page 31: Groovy, in the light of Java 8

Lambda expressions

21

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

In Groovy, that would be…

Page 32: Groovy, in the light of Java 8

Lambda expressions

21

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

Drawback: intermediary data structures Unless you use iterator variants

Page 33: Groovy, in the light of Java 8

Lambda expressions

21

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

Page 34: Groovy, in the light of Java 8

The various lambda syntaxes

22

String name -> name.length() !

(int left, int right) -> left + right !

(String left, String sep, String right) -> { System.out.println(left + sep + right) }

Page 35: Groovy, in the light of Java 8

The various lambda syntaxes

22

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

Page 36: Groovy, in the light of Java 8

The various lambda syntaxes

22

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

Page 37: Groovy, in the light of Java 8

The various lambda syntaxes

22

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

Page 38: Groovy, in the light of Java 8

The various lambda syntaxes

22

String name -> name.length() !

(int left, int right) -> left + right !

(String left, String sep, String right) -> { System.out.println(left + sep + right) }

Page 39: Groovy, in the light of Java 8

The various lambda syntaxes

23

name -> name.length() !

(left, right) -> left + right !

(left, sep, right) -> { System.out.println(left + sep + right) }

Page 40: Groovy, in the light of Java 8

The various lambda syntaxes

23

name -> name.length() !

(left, right) -> left + right !

(left, sep, right) -> { System.out.println(left + sep + right) }

Clever type inference can help get rid of parameter

type declarations

Page 41: Groovy, in the light of Java 8

Closures vs lambdas

24

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

Page 42: Groovy, in the light of Java 8

Closures vs lambdas

24

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 }

Page 43: Groovy, in the light of Java 8

Closures vs lambdas

24

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

Page 44: Groovy, in the light of Java 8

Closures vs lambdas

24

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)

Page 45: Groovy, in the light of Java 8

Closures vs lambdas

24

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 }

Page 46: Groovy, in the light of Java 8

Beyond: Closure default parameters

25

def mult = { int a, int b = 10 -> a * b } !

assert mult(2, 3) == 6 assert mult(5) == 50

Page 47: Groovy, in the light of Java 8

Beyond: Closure default parameters

25

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

Page 48: Groovy, in the light of Java 8

Beyond: Duck typing polymorphism

26

def adder = { a, b -> a + b } !

assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY'

Page 49: Groovy, in the light of Java 8

Beyond: Duck typing polymorphism

26

def adder = { a, b -> a + b } !

assert adder(100, 200) == 300 assert adder('X', 'Y') == 'XY'

Works both for numbers and for strings

Page 50: Groovy, in the light of Java 8

Builders

Page 51: Groovy, in the light of Java 8

BuildersWhat would Java lambda

builders look like?

Page 52: Groovy, in the light of Java 8

BuildersWhat would Java lambda

builders look like?

Aren’t Groovy builders more powerful?

Page 53: Groovy, in the light of Java 8

Lambda-based builders uglier and less powerful

28

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

Page 54: Groovy, in the light of Java 8

Lambda-based builders uglier and less powerful

28

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

Page 55: Groovy, in the light of Java 8

Lambda-based builders uglier and less powerful

28

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

Page 56: Groovy, in the light of Java 8

Lambda-based builders uglier and less powerful

28

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

Page 57: Groovy, in the light of Java 8

Neater Groovy builder!

29

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

Page 58: Groovy, in the light of Java 8

Neater Groovy builder!

29

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

Page 59: Groovy, in the light of Java 8
Page 60: Groovy, in the light of Java 8

Aren’t Groovy builders more readable and lean?

Page 61: Groovy, in the light of Java 8

To those who said no…

31

Page 62: Groovy, in the light of Java 8

Memoization

Page 63: Groovy, in the light of Java 8

Closure and method memoization

33

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

Page 64: Groovy, in the light of Java 8

Closure and method memoization

33

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

Closures:memoize()

Page 65: Groovy, in the light of Java 8

Closure and method memoization

33

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

Page 66: Groovy, in the light of Java 8

Closure and method memoization

33

@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

Page 67: Groovy, in the light of Java 8
Page 68: Groovy, in the light of Java 8

Tail recursion

Page 69: Groovy, in the light of Java 8

Closure and method tail recursion

35

def fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline()

Page 70: Groovy, in the light of Java 8

Closure and method tail recursion

35

def fact = { n, accu = 1G -> if (n < 2) accu else fact.trampoline(n - 1, n * accu) }.trampoline()

Closures:Tail recursion with

trampoline()

Page 71: Groovy, in the light of Java 8

Closure and method tail recursion

35

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

Page 72: Groovy, in the light of Java 8

Closure and method tail recursion

35

@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

@TailRecursivetransformation

Page 73: Groovy, in the light of Java 8

Method references

36

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

Page 74: Groovy, in the light of Java 8

Method references

36

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

button.setOnAction(System.out::println);

Page 75: Groovy, in the light of Java 8

Method references — 3 main cases

37

instance::instanceMethod !

SomeClass::staticMethod !

SomeClass::instanceMethod

Page 76: Groovy, in the light of Java 8

Method references — 3 main cases

37

instance::instanceMethod !

SomeClass::staticMethod !

SomeClass::instanceMethod

Not covered by Groovy method

closures yet!

Page 77: Groovy, in the light of Java 8

Groovy’s method closure

38

instance.&instanceMethod !

SomeClass.&staticMethod !

SomeClass.&instanceMethod

Page 78: Groovy, in the light of Java 8

Groovy’s method closure

38

instance.&instanceMethod !

SomeClass.&staticMethod !

SomeClass.&instanceMethod

Choices:Adopt ::

Deprecate .& Enhance .&

Page 79: Groovy, in the light of Java 8

Static methods in interfaces

• You can put static utility methods in interfaces, instead of in companion classes (like « Collections »)

39

public interface Stream<T> { // ... static <T> Stream<T> empty() { return new Stream<T> { ... } } }

Page 80: Groovy, in the light of Java 8

Default methods in interfaces

• Define default behavior • possibly to enrich existing interfaces

40

public interface Stream<T> { // ... default Builder<T> add(T t) { ... } }

Page 81: Groovy, in the light of Java 8

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 41

Page 82: Groovy, in the light of Java 8

Simple trait

42

trait FlyingAbility { String fly() { "I'm flying!" } } !

class Bird implements FlyingAbility {} def b = new Bird() !

assert b.fly() == "I'm flying!"

Page 83: Groovy, in the light of Java 8

Trait with state

43

trait Named { String name } !

class Bird implements Named {} def b = new Bird(name: 'Colibri') !

assert b.name == 'Colibri'

Page 84: Groovy, in the light of Java 8

Multiple inheritance

44

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'

Page 85: Groovy, in the light of Java 8

To know all about traits!

45

Rethinking API design with traits by Cédric Champeau Tue 2:30pm / Trinity 3

Page 86: Groovy, in the light of Java 8

Annotations on types

Repeating annotations

Page 87: Groovy, in the light of Java 8

Repeating annotations

47

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

Page 88: Groovy, in the light of Java 8

Repeating annotations

47

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

@Schedule annotation repeated twice

Page 89: Groovy, in the light of Java 8

Repeating annotations

47

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

Page 90: Groovy, in the light of Java 8

Repeating annotations

47

@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

Page 91: Groovy, in the light of Java 8

Repeating annotations

47

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

Page 92: Groovy, in the light of Java 8

Repeating annotations

47

@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

Page 93: Groovy, in the light of Java 8

Repeating annotations

47

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

Page 94: Groovy, in the light of Java 8

Repeating annotations

47

@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

Page 95: Groovy, in the light of Java 8

Repeating annotations

47

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

Page 96: Groovy, in the light of Java 8

Annotations on types

• Everywhere you can put a type, you can put an annotation

48

@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> {...}

Page 97: Groovy, in the light of Java 8

Annotations on types

• Everywhere you can put a type, you can put an annotation

48

@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

Page 98: Groovy, in the light of Java 8

Annotations on types

• Everywhere you can put a type, you can put an annotation

48

@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?

Page 99: Groovy, in the light of Java 8

Annotations on types

• Everywhere you can put a type, you can put an annotation

48

@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> {...}

Page 100: Groovy, in the light of Java 8

Groovy compile-time meta-annotations

49

@Service @Transactional class MyTransactionalService {}

Page 101: Groovy, in the light of Java 8

Groovy compile-time meta-annotations

49

@Service @Transactional class MyTransactionalService {}

import groovy.transform.AnnotationCollector !@Service @Transactional @AnnotationCollector public @interface TransactionalService {}

Page 102: Groovy, in the light of Java 8

Groovy compile-time meta-annotations

49

import groovy.transform.AnnotationCollector !@Service @Transactional @AnnotationCollector public @interface TransactionalService {}

!@TransactionalService class MyTransactionalService {}

Page 103: Groovy, in the light of Java 8

Groovy compile-time meta-annotations

49

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 »

Page 104: Groovy, in the light of Java 8

Groovy compile-time meta-annotations

49

import groovy.transform.AnnotationCollector !@Service @Transactional @AnnotationCollector public @interface TransactionalService {}

!@TransactionalService class MyTransactionalService {}

Page 105: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

New Java 8 APIs

Page 106: Groovy, in the light of Java 8

Date and

Time API

Page 107: Groovy, in the light of Java 8

Date / Time API

52

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

Page 108: Groovy, in the light of Java 8

Date / Time API

52

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?

Page 109: Groovy, in the light of Java 8

Date / Time API

52

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

Page 110: Groovy, in the light of Java 8

Groovy’s date / time handling

53

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 }

Page 111: Groovy, in the light of Java 8

Groovy’s date / time handling

53

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

Page 112: Groovy, in the light of Java 8

Groovy’s date / time handling

53

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 }

Page 113: Groovy, in the light of Java 8

Stream API

Page 114: Groovy, in the light of Java 8

map

map

map

map

map

reducereduce reduce

reduce

reduce

Page 115: Groovy, in the light of Java 8

map

map

map

map

map

reducereduce reduce

reduce

reduce

Map / filter / reduce explained to

your 6 year old

Page 116: Groovy, in the light of Java 8

map

map

map

map

map

reducereduce reduce

reduce

reduce

Page 117: Groovy, in the light of Java 8

Stream

56

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

Page 118: Groovy, in the light of Java 8

Groovy’s functional style with the GDK methods

57

persons .findAll { it.getAge() < 18 } .collect { it.name.toUpperCase() } .sort() .joining(", ")

Page 119: Groovy, in the light of Java 8

Groovy using streams too!

58

persons.stream() .filter { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))

Page 120: Groovy, in the light of Java 8

Groovy using streams too!

58

persons.stream() .filter { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))

Leveraging closure to « SAM » type coercion

Page 121: Groovy, in the light of Java 8

Groovy using streams too!

58

persons.stream() .filter { it.age < 18 } .map { it.name.toUpperCase() } .sorted() .collect(Collectors.joining(", "))

Page 122: Groovy, in the light of Java 8

Optional

59

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

Page 123: Groovy, in the light of Java 8

Optional

59

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

Page 124: Groovy, in the light of Java 8

Optional

59

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

Page 125: Groovy, in the light of Java 8

Optional

59

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

Page 126: Groovy, in the light of Java 8

Optional

59

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

Page 127: Groovy, in the light of Java 8
Page 128: Groovy, in the light of Java 8

You know you can customize the truth in Groovy?

Page 129: Groovy, in the light of Java 8

You know you can customize the truth in Groovy?

Just implement a custom asBoolean() method!

Page 130: Groovy, in the light of Java 8

The law of Groovy Truth

61

Page 131: Groovy, in the light of Java 8

The law of Groovy Truth

61

Everything that’s null, empty, zero-sized, equal

to zero is false

Page 132: Groovy, in the light of Java 8

The law of Groovy Truth

61

Everything that’s null, empty, zero-sized, equal

to zero is false

Otherwise, it’s true!

Page 133: Groovy, in the light of Java 8

?:

Page 134: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

def maybeName = Optional.of("Guillaume") !def result = maybeName ?: "unknown" !if (maybeName) { println maybeName.get() } else { println "unknown" } !maybeName?.toUpperCase()

Page 135: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

def maybeName = Optional.of("Guillaume") !def result = maybeName ?: "unknown" !if (maybeName) { println maybeName.get() } else { println "unknown" } !maybeName?.toUpperCase()

Elvis!

Page 136: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

def maybeName = Optional.of("Guillaume") !def result = maybeName ?: "unknown" !if (maybeName) { println maybeName.get() } else { println "unknown" } !maybeName?.toUpperCase()

Groovy Truth!

Page 137: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

def maybeName = Optional.of("Guillaume") !def result = maybeName ?: "unknown" !if (maybeName) { println maybeName.get() } else { println "unknown" } !maybeName?.toUpperCase()

Safe navigation

Page 138: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

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

Page 139: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

def maybeName = Optional.of("Guillaume") !def result = maybeName ?: "unknown" !if (maybeName) { println maybeName.get() } else { println "unknown" } !maybeName?.toUpperCase()

Not Yet Implemented

Page 140: Groovy, in the light of Java 8

Groovy truth, null handling, Elvis with Optional

63

def maybeName = Optional.of("Guillaume") !def result = maybeName ?: "unknown" !if (maybeName) { println maybeName.get() } else { println "unknown" } !maybeName?.toUpperCase()

Page 141: Groovy, in the light of Java 8

Nashorn

Page 142: Groovy, in the light of Java 8

Nashorn

Speak German?

Page 143: Groovy, in the light of Java 8

Call JavaScript from Groovy with JSR-223

65

def manager = new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") !

assert engine.eval("{} + []") == 0

Page 144: Groovy, in the light of Java 8

Call JavaScript from Groovy with JSR-223

65

def manager = new ScriptEngineManager() def engine = manager.getEngineByName("nashorn") !

assert engine.eval("{} + []") == 0

Sane JavaScript logic :-)

Page 145: Groovy, in the light of Java 8

GrooScript — http://grooscript.org/

66

JS

Page 146: Groovy, in the light of Java 8

GrooScript — http://grooscript.org/

66

JSGradle & Grails plugins available

Examples available with Ratpack, Node.JS…

Page 147: Groovy, in the light of Java 8

Turtles all the way down!

Page 148: Groovy, in the light of Java 8

Turtles all the way down!

Full Groovy!

Page 149: Groovy, in the light of Java 8

Turtles all the way down!

Full Groovy!

Back to front

Page 150: Groovy, in the light of Java 8

Turtles all the way down!

Full Groovy!

Back to front

Front to back

Page 151: Groovy, in the light of Java 8
Page 152: Groovy, in the light of Java 8

Jackson Pollock

Page 153: Groovy, in the light of Java 8

JavaFx… !

!

…the new Swing

Page 154: Groovy, in the light of Java 8

GroovyFX

70

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

Page 155: Groovy, in the light of Java 8

GroovyFX

70

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!

Page 156: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Beyond Java

Page 157: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Easy scripting

Page 158: Groovy, in the light of Java 8

Scripting

73

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc" .execute().waitFor() tmpHtml.delete() } }

<html/>

AsciiDoctor

Page 159: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Page 160: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Use @Grab to download the htmlcleaner library

Page 161: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Page 162: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Setup HtmlCleaner

Page 163: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Page 164: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Recursively find all the files to transform

Page 165: Groovy, in the light of Java 8

Ant scripting

74

@Grab('net.sourceforge.htmlcleaner:htmlcleaner:2.4') import org.htmlcleaner.* !def src = new File('html').toPath() def dst = new File('asciidoc').toPath() !def cleaner = new HtmlCleaner() def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text

Page 166: Groovy, in the light of Java 8

Ant scripting

75

def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc"

Page 167: Groovy, in the light of Java 8

Ant scripting

75

def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc"

Clean the HTML

Page 168: Groovy, in the light of Java 8

Ant scripting

75

def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc"

Page 169: Groovy, in the light of Java 8

Ant scripting

75

def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc"

Some more clean-up

Page 170: Groovy, in the light of Java 8

Ant scripting

75

def props = cleaner.properties props.translateSpecialEntities = false def serializer = new SimpleHtmlSerializer(props) !src.toFile().eachFileRecurse { f -> def relative = src.relativize(f.toPath()) def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc"

Page 171: Groovy, in the light of Java 8

Ant scripting

76

def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc" .execute().waitFor() tmpHtml.delete() } }

Page 172: Groovy, in the light of Java 8

Ant scripting

76

def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc" .execute().waitFor() tmpHtml.delete() } }

Write the result

Page 173: Groovy, in the light of Java 8

Ant scripting

76

def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc" .execute().waitFor() tmpHtml.delete() } }

Page 174: Groovy, in the light of Java 8

Ant scripting

76

def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc" .execute().waitFor() tmpHtml.delete() } }

Call an external process to convert and wait for its execution

Page 175: Groovy, in the light of Java 8

Ant scripting

76

def target = dst.resolve(relative) if (f.isDirectory()) { target.toFile().mkdir() } else if (f.name.endsWith('.html')) { def tmpHtml = File.createTempFile('clean', 'html') println "Converting $relative" def result = cleaner.clean(f) result.traverse({ tagNode, htmlNode -> tagNode?.attributes?.remove 'class' if ('td' == tagNode?.name || 'th'==tagNode?.name) { tagNode.name='td' String txt = tagNode.text tagNode.removeAllChildren() tagNode.insertChild(0, new ContentNode(txt)) } true } as TagNodeVisitor) serializer.writeToFile( result, tmpHtml.absolutePath, "utf-8" ) "pandoc -f html -t asciidoc -R -S --normalize -s $tmpHtml -o ${target}.adoc" .execute().waitFor() tmpHtml.delete() } }

Page 176: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Android

Page 177: Groovy, in the light of Java 8

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

78

Page 178: Groovy, in the light of Java 8

New York Times — Getting Groovy with Android

79

Page 179: Groovy, in the light of Java 8

New York Times — Getting Groovy with Android

79

http://bit.ly/nyt-groovy

Page 180: Groovy, in the light of Java 8

What does NYT likes about Groovy on Android?

• No Java 8, no lambda on Android…

80

Func0 func = new Func0<string>() { @Override public String call() { return "my content"; } }; Async.start(func);

Page 181: Groovy, in the light of Java 8

What does NYT likes about Groovy on Android?

• No Java 8, no lambda on Android…

81

!

!

!

!

!

!

Async.start { "my content" }

Page 182: Groovy, in the light of Java 8

What does NYT likes about Groovy on Android?

• No Java 8, no lambda on Android…

81

!

!

!

!

!

!

Async.start { "my content" }

Good bye annonymous inner classes!

Page 183: Groovy, in the light of Java 8

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)

82

Page 184: Groovy, in the light of Java 8

Android support

83

Page 185: Groovy, in the light of Java 8

Android support

83

Page 186: Groovy, in the light of Java 8

Android support

83

Source code available:https://github.com/melix/gr8confagenda

Page 187: Groovy, in the light of Java 8

To know all about Android support

84

Groovy & Android, a winning pair? by Cédric Champeau Thu 12:45pm / Trinity 3

Page 188: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

A rich Groovy ecosystem

Page 189: Groovy, in the light of Java 8

Grails — web framework

86

@Grab("com.h2database:h2:1.3.173") import grails.persistence.* !

@Entity @Resource(uri='/books') class Book { String title }

Page 190: Groovy, in the light of Java 8

Grails — web framework

86

@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!

Page 191: Groovy, in the light of Java 8

Ratpack — web framework

87

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

Page 192: Groovy, in the light of Java 8

Ratpack — web framework

87

@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

Page 193: Groovy, in the light of Java 8

@ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true }

Griffon — rich desktop applications

88

Page 194: Groovy, in the light of Java 8

@ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true }

Griffon — rich desktop applications

88

Model

Page 195: Groovy, in the light of Java 8

@ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true }

Griffon — rich desktop applications

88

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

Page 196: Groovy, in the light of Java 8

@ArtifactProviderFor(GriffonModel) class ConsoleModel { String scriptSource @Observable Object scriptResult @Observable boolean enabled = true }

Griffon — rich desktop applications

88

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

Page 197: Groovy, in the light of Java 8

Spock — unit testing & specification

89

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

Page 198: Groovy, in the light of Java 8

Spock — unit testing & specification

89

@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

Page 199: Groovy, in the light of Java 8

Spock — unit testing & specification

89

@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

Page 200: Groovy, in the light of Java 8

Geb — browser automation

90

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

Page 201: Groovy, in the light of Java 8

Geb — browser automation

90

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

Page 202: Groovy, in the light of Java 8

Geb — browser automation

90

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

Page 203: Groovy, in the light of Java 8

Geb — browser automation

90

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

Page 204: Groovy, in the light of Java 8

Gradle — build automation

91

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

Page 205: Groovy, in the light of Java 8

Gradle — build automation

91

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

Page 206: Groovy, in the light of Java 8

GPars — concurrency / parallelism / async / …

92

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

Page 207: Groovy, in the light of Java 8

GPars — concurrency / parallelism / async / …

92

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…

Page 208: Groovy, in the light of Java 8

GPars — concurrency / parallelism / async / …

92

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

Page 209: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Groovy modules

Page 210: Groovy, in the light of Java 8

Groovy modules

• Ant scripting • JMX • JSON • Servlet • Swing • SQL • Templating • Testing • XML

94

Page 211: Groovy, in the light of Java 8

Groovy modules

• Ant scripting • JMX • JSON • Servlet • Swing • SQL • Templating • Testing • XML

95

Page 212: Groovy, in the light of Java 8

Ant + XML

96

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

Page 213: Groovy, in the light of Java 8

Ant + XML

96

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

Page 214: Groovy, in the light of Java 8

Ant + XML

96

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

Page 215: Groovy, in the light of Java 8

Ant + XML

96

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

Page 216: Groovy, in the light of Java 8

JSON support — creating JSON

97

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

Page 217: Groovy, in the light of Java 8

JSON support — creating JSON

97

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

Page 218: Groovy, in the light of Java 8

JSON support — parsing JSON

98

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'

Page 219: Groovy, in the light of Java 8

JSON support — parsing JSON

98

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!

Page 220: Groovy, in the light of Java 8

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 99

Page 221: Groovy, in the light of Java 8

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 99

Spring Boot approved

Page 222: Groovy, in the light of Java 8

Markup template engine — the idea

100

cars { cars.each { car(make: it.make, name: it.name) } }

Page 223: Groovy, in the light of Java 8

Markup template engine — the idea

100

cars { cars.each { car(make: it.make, name: it.name) } }

Your template

Page 224: Groovy, in the light of Java 8

Markup template engine — the idea

100

cars { cars.each { car(make: it.make, name: it.name) } }

model = [cars: [ new Car(make: 'Peugeot', name: '508'), new Car(make: 'Toyota', name: 'Prius’) ]]

Page 225: Groovy, in the light of Java 8

Markup template engine — the idea

100

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

Page 226: Groovy, in the light of Java 8

Markup template engine — the idea

100

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>

Page 227: Groovy, in the light of Java 8

Markup template engine — the idea

100

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

Page 228: Groovy, in the light of Java 8

Markup template engine — the idea

100

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>

Page 229: Groovy, in the light of Java 8

Markup template engine — in action

101

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)

Page 230: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Summary

Page 231: Groovy, in the light of Java 8

Back to our original question…

103

Do we still need Groovy now that we

have Java 8?

Page 232: Groovy, in the light of Java 8
Page 233: Groovy, in the light of Java 8

Longer answer: Yes, because…

• You can benefit from Java 8 in Groovy

105

Synergy the whole is greater than the sum of the parts

Page 234: Groovy, in the light of Java 8

Longer answer: Yes, because…

• Groovy goes beyond what Java 8 offers

106

BeyondGroovy always

tries to add something to the table

Page 235: Groovy, in the light of Java 8

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

107

Page 236: Groovy, in the light of Java 8

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

108

Page 237: Groovy, in the light of Java 8

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

108

Community feedback &

contributions welcome!

Page 238: Groovy, in the light of Java 8

More Java 8 coverage

109

Java 8 language capabilities by V. Subramaniam Thu 10:30pm / D.Ball.G

Page 239: Groovy, in the light of Java 8

More Java 8 coverage

110

How to get Groovy with Java 8 by Peter Ledbrook Thu 10:30pm / Trinity 3

Page 240: Groovy, in the light of Java 8

Java 8 in Action

!

• By Urma, Fusco and Mycrof • Plublished by Manning • http://www.manning.com/urma/

111

Page 241: Groovy, in the light of Java 8

© 2014 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Q & A

Page 242: Groovy, in the light of Java 8
Page 243: Groovy, in the light of Java 8

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 114

Page 244: Groovy, in the light of Java 8

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

115

Page 245: Groovy, in the light of Java 8

Image credits

• Jackson Pollock • http://www.ibiblio.org/wm/paint/auth/pollock/pollock.number-8.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

• 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 116