+ All Categories
Home > Education > Java SE 8 for Java EE developers

Java SE 8 for Java EE developers

Date post: 16-Apr-2017
Category:
Upload: jose-paumard
View: 3,328 times
Download: 1 times
Share this document with a friend
84
@ Delabassee @ JosePaumard #SE84EE Java EE devs Java SE 8 for
Transcript

@Delabassee @JosePaumard#SE84EE

Java EE devs

Java SE 8 for

@Delabassee @JosePaumard#Devoxx #SE84EE

Agenda

Java SE 8 has been released ~1.5 year ago

Java EE 7 Application Servers

- GlassFish, WildFly, Liberty Profile, WebLogic, etc.

@Delabassee @JosePaumard#Devoxx #SE84EE

Agenda

Java SE 8 has been released ~1.5 year ago

Java EE 7 Application Servers

- GlassFish, WildFly, Liberty Profile, WebLogic, etc.

Check some important Java SE 8 new features

for Java EE developers... with patterns!

@Delabassee

@JosePaumard

@JosePaumard

start

The following is intended to outline our general product direction.

It is intended for information purposes only, and may not be

incorporated into any contract. It is not a commitment to deliver

any material, code, or functionality, and should not be relied upon

in making purchasing decisions. The development, release, and

timing of any features or functionality described for Oracle’s

products remains at the sole discretion of Oracle.

@Delabassee @JosePaumard#Devoxx #SE84EE

Questions?

#SE84EE

http://slido.com

Date

@Delabassee @JosePaumard#Devoxx #SE84EE

New Date & Time API

Date & Time API is a new introduction in Java 8

Initiated by Stephen Colebourne, based on Joda Time

Complete replacement of Date & Calendar

@Delabassee @JosePaumard#Devoxx #SE84EE

Date: ZonedTime

Useful for localized times

Set<String> allZonesIds = ZoneId.getAvailableZoneIds() ;

String ukTZ = ZoneId.of("Europe/Paris") ;

@Delabassee @JosePaumard#Devoxx #SE84EE

Date: ZonedTime

Useful for localized times

System.out.println(ZonedDateTime.of(

1998, Month.JULY.getValue(), 12, // year / month / day22, 0, 0, 0, // h / mn / s / nanosZoneId.of("Europe/Paris"))

); // prints 1998-07-22T22:00-00:01:15[Europe/London]

@Delabassee @JosePaumard#Devoxx #SE84EE

Date: ZonedTime

Useful for localized times

System.out.println(ZonedDateTime.of(

1998, Month.JULY.getValue(), 12, // year / month / day22, 0, 0, 0, // h / mn / s / nanosZoneId.of("Europe/Paris"))

);

ZonedDateTime nextWorldCup = currentWorldCup.plus(Period.ofYear(4));

@Delabassee @JosePaumard#Devoxx #SE84EE

Date: ZonedTime

Useful for localized times

System.out.println(ZonedDateTime.of(

1998, Month.JULY.getValue(), 12, // year / month / day22, 0, 0, 0, // h / mn / s / nanosZoneId.of("Europe/Paris"))

);

ZonedDateTime nextWorldCup = currentWorldCup.plus(Period.ofYear(4));

ZonedDateTime nexWorldCupJapan= nextWorldCup.withZoneSameInstant(ZoneId.of("Asia/Tokyo")) ;

@Delabassee @JosePaumard#Devoxx #SE84EE

Date: bridges with java.util.Date

Conversions between j.u.Date and Date & Time

Time time = Time.from(localTime); // API -> legacyLocalTime localTime = time.toLocalTime(); // legacy -> new API

Date date = Date.from(localDate); // API -> legacyLocalDate localDate = date.toLocalDate(); // legacy -> new API

TimeStamp time = TimeStamp.from(instant); // API -> legacyInstant instant = time.toInstant(); // legacy -> new API

Date date = Date.from(instant); // API -> legacyInstant instant = date.toInstant(); // legacy -> new API

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JPA

JPA does not support this Date & Time API (yet)

But with converters, we can still use it

@Entitypublic abstract class AbstractPersistent {

@Convert(converter=DateConverter.class)private Instant instant;

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JPA

The converter is a classical object

public class DateConverterimplements AttributeConverter<Instant, Date> {

public Date convertToDatabaseColumn(Instant instant) {return Date.from(instant);

}

public Instant convertToEntityAttribute(Date date) {return date.toInstant();

}}

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JPA

The converter is a classical object

public class DateFormatConverterimplements AttributeConverter<ZonedDateTime, String> {

public String convertToDatabaseColumn(ZonedDateTime time) {return DateTimeFormatter.ISO_DATE_TIME.format(time);

}

public ZonedDateTime convertToEntityAttribute(String formated) {return DateTimeFormatter.ISO_DATE_TIME

.parse(formated, ZonedDateTime::from);}

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JPA

With JPA converters we can use the types

from Date & Time API and map in j.u.l.Date or String

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JSF

With a Custom JSF Converter

@FacesConverter("instantConverter")public class TimeConverter implements javax.faces.convert.Converter {

@Overridepublic Object getAsObject(FacesContext ctx, … , String value) {

return Instant.parse(value);}

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JSF

With a Custom JSF Converter...@Overridepublic String getAsString(FacesContext ctx, … , Object value) {

DateTimeFormatter formatter =DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)

.withLocale(Locale.US)

.withZone(ZoneId.systemDefault());

return formatter.format((TemporalAccessor) value);}

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Usable in JSF

With a Custom JSF Converter<h:form><h:inputText id = "date”

value = "#{order.timestamp}" size = "20" required="true”label = "start"

converter = "instantConverter" />...

@ManagedBean(name="order") @SessionScopedpublic class myBean implements Serializable{

Instant timestamp;…

Annotations

@Delabassee @JosePaumard#Devoxx #SE84EE

Annotations in Java 7

Wrapping annotations

An annotation cannot be applied more than once

@NamedQueries({@NamedQuery(name=SELECT_ALL, query="..."), @NamedQuery(name=COUNT_ALL, query="...")

})public class Customer {

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Annotations in Java 8

Java 8 makes it possible!

@NamedQuery(name=SELECT_ALL, query="..."), @NamedQuery(name=COUNT_ALL, query="...")public class Customer {

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Bean Validation

Suppose we want to validate a parameter

public orderdCar order( @CheckCar("VW") Car aCar ) { ...

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Bean Validation

Here is the Bean Validation code for @CheckCar

@Target({PARAMETER})@Retention(RUNTIME)@Constraint(validatedBy = CarValidator.class)public @interface CheckCar {

Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};String value();

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Bean Validation

And for the validator

public class CarValidatorimplements ConstraintValidator<CheckCar, Car> {

private String carBrand;

public void initialize(CheckCar constraintAnnotation) {this.carBrand = constraintAnnotation.value();

}

public boolean isValid(Car obj, ConstraintValidatorContext ctrCtx) {if (object == null) return true;return (!obj.getBrand().toUpperCase().contains(carBrand));

}

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Bean Validation

And the Java 8 trick to make it repeatable

@Target({PARAMETER})@Retention(RUNTIME)@Repeatable(CheckCars.class)@Constraint(validatedBy = CarValidator.class)public @interface CheckCar {

Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};String value();

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Bean Validation

And the Java 8 trick to make it repeatable

@Target({PARAMETER})@Retention(RUNTIME)public @interface CheckCars {

CheckCar[] value() default{};}

@Delabassee @JosePaumard#Devoxx #SE84EE

Bean Validation

Suppose we want to validate a parameter

public orderdCar order( @CheckCar("VW") @ChechCar("Audi") Car aCar ) { ...

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Type annotations

Annotations can be now put on types

Example 1: tell that a variable should not be null

private @NonNull List<Person> persons = ... ;

@Delabassee @JosePaumard#Devoxx #SE84EE

Type annotations

Annotations can be now put on types

Example 1: tell that a variable should not be null

Example 2: the content should not be null neither

private @NonNull List<Person> persons = ... ;

private @NonNull List<@NonNull Person> persons = ... ;

String

@Delabassee @JosePaumard#Devoxx #SE84EE

Joining strings

New String joiners are coming to the JDK!

@Delabassee @JosePaumard#Devoxx #SE84EE

Joining strings

StringJoiner class

And it prints:

StringJoiner sj = new StringJoiner(", ") ;

sj.add("one").add("two").add("three") ;String s = sj.toString() ;System.out.println(s) ;

> one, two, three

@Delabassee @JosePaumard#Devoxx #SE84EE

Joining strings

StringJoiner with prefix / postfix

And it prints:

StringJoiner sj = new StringJoiner(", ", "{", "}") ;

sj.add("one").add("two").add("three") ;String s = sj.toString() ;System.out.println(s) ;

> {one, two, three}

@Delabassee @JosePaumard#Devoxx #SE84EE

Joining strings

Also accessible from the String class

And it prints:

// From the String class, with a varargString s = String.join(", ", "one", "two", "three");System.out.println(s);

> one, two, three

@Delabassee @JosePaumard#Devoxx #SE84EE

Joining strings

And directly from a List

// From a list to a String using the Stream & Collectors APIString s =

listOfStrings.stream().collect(Collectors.joining(", "));

System.out.println(s);

> one, two, three

@Delabassee @JosePaumard#Devoxx #SE84EE

Joining strings

And directly from a List

The result is

// From the String class, with a varargString s =

listOfStrings.stream().collect(Collectors.joining(", ", "{", "}"));

System.out.println(s);

> {one, two, three}

@Delabassee @JosePaumard#Devoxx #SE84EE

Support for Base64 decoding

After a few years…

import java.util.Base64;

String txt = "Modern Times!";

String encoded = Base64.getEncoder().encodeToString(txt.getBytes(StandardCharsets.UTF_8));

String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);

Streams

@Delabassee @JosePaumard#Devoxx #SE84EE

What is a Stream?

A new API

A typed interface

A new concept

@Delabassee @JosePaumard#Devoxx #SE84EE

What is a Stream?

A new API

A typed interface

A new concept

Let’s see some code!

@Delabassee @JosePaumard#Devoxx #SE84EE

Readable and efficient patterns

Extract histograms from data

List<Person> people = Arrays.asList();

Map<City, Double> agesByCity = people.stream()

.filter(p -> p.getAge() > 20)

.collect(Collectors.groupingBy(

Person::getCity, Collectors.averagingDouble(Person::getAge)

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Readable and efficient patterns

Extract histograms from data

List<Person> people = Arrays.asList();

Map<City, Double> agesByCity = people.stream()

.filter(p -> p.getAge() > 20)

.collect(Collectors.groupingBy(

Person::getCity, Collectors.averagingDouble(Person::getAge)

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Readable and efficient patterns

Extract histograms from data

List<Person> people = Arrays.asList();

Map<City, Double> agesByCity = people.stream()

.filter(p -> p.getAge() > 20)

.collect(Collectors.groupingBy(

Person::getCity, Collectors.averagingDouble(Person::getAge)

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Readable and efficient patterns

Extract histograms from data

List<Person> people = Arrays.asList();

Map<City, Double> agesByCity = people.stream()

.filter(p -> p.getAge() > 20)

.collect(Collectors.groupingBy(

Person::getCity, Collectors.averagingDouble(Person::getAge)

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Readable and efficient patterns

Extract histograms from data

List<Person> people = Arrays.asList();

Map<City, Double> agesByCity = people.stream()

.filter(p -> p.getAge() > 20)

.collect(Collectors.groupingBy(

Person::getCity, Collectors.averagingDouble(Person::getAge)

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Readable and efficient patterns

Extract histograms from data

List<Person> people = Arrays.asList();

Map<City, Double> agesByCity = people.stream()

.filter(p -> p.getAge() > 20)

.collect(Collectors.groupingBy(

Person::getCity, Collectors.averagingDouble(Person::getAge)

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Building a Stream on a String

Building a Stream on the letters of a String:

String s = "hello";IntStream stream = s.chars(); // stream on the letters of s

@Delabassee @JosePaumard#Devoxx #SE84EE

Building a Stream on a String

Building a Stream on the letters of a String:

String s = "hello";IntStream stream = s.chars(); // stream on the letters of s

s.chars() // IntStream.mapToObj(letter -> (char)letter) // Stream<Character>.map(Character::toUpperCase).forEach(System.out::println); // Prints a Character

> HELLO

@Delabassee @JosePaumard#Devoxx #SE84EE

Build a Stream from a text file

Find the first error line from a log file

// Java 7 : try with resources and use of PathsPath path = Paths.get("d:", "tmp", "debug.log");try (Stream<String> stream = Files.lines(path)) {

stream.filter(line -> line.contains("ERROR")).findFirst().ifPresent(System.out::println);

} catch (IOException ioe) {// handle the exception

}

@Delabassee @JosePaumard#Devoxx #SE84EE

Build a Stream from a regex

Building a Stream from a regexp

// book is a looooooooong StringStream<String> words =

Pattern.compile(" ").splitAsStream(book) ;

@Delabassee @JosePaumard#Devoxx #SE84EE

Build a Stream from a regex

Building a Stream from a regexp

More efficient than:

// book is a looooooooong StringStream<String> words =

Pattern.compile(" ").splitAsStream(book) ;

// book is a looooooooong StringStream<String> words =

Stream.of(book.split(" "));

@Delabassee @JosePaumard#Devoxx #SE84EE

Flatmap: Files.lines + regex

Splitting a text files into words

Stream<String> streamOfLines = Files.lines(path);

Function<String, Stream<String>> splitter = line -> Pattern.compile(" ").splitAsStream(line);

long numberOfWords = streamOfLines.flatMap(splitter)

.map(String::toLowerCase)

.distinct()

.count();

@Delabassee @JosePaumard#Devoxx #SE84EE

Why is it important for Java EE?

Given this JSON file

[

{

"name":"Duke",

"gender":"m",

"phones":[

"home":"650‐123‐4567","mobile":"650‐111‐2222"

]

},

{

"name":"Jane", …

]

JsonArray contacts = Json.createArrayBuilder()

.add(…

@Delabassee @JosePaumard#Devoxx #SE84EE

Why is it important for Java EE?

And some JSON-P magic

Map<String, Long> names = contacts.getValuesAs(JsonObject.class).stream()

.filter(x -> "f".equals(x.getString("gender")))

.map(x -> (x.getString("name")))

.collect(Collectors.groupingBy(

Function.identity(),Collectors.counting()

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Why is it important for Java EE?

// TodayJsonArray names =

contacts.getValuesAs(JsonObject.class).stream().filter(x -> "f".equals(x.getString("gender"))).map(x -> (x.getString("name"))).collect(

Collector.of(() -> Json.createArrayBuilder(), (builder, value) -> builder.add(value),(builder1, builder2) -> builder1.add(builder2), builder -> builder.build()

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Why is it important for Java EE?

// TodayJsonArray names =

contacts.getValuesAs(JsonObject.class).stream().filter(x -> "f".equals(x.getString("gender"))).map(x -> (x.getString("name"))).collect(

Collector.of(Json::createArrayBuilder, JsonArrayBuilder::add,JsonArrayBuilder::add, JsonArrayBuilder::build

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Why is it important for Java EE?

// TodayJsonArray names =

contacts.getValuesAs(JsonObject.class).stream().filter(x -> "f".equals(x.getString("gender"))).map(x -> (x.getString("name"))).collect(

Collectors.collectingAndThen(Collector.of(

Json::createArrayBuilder, JsonArrayBuilder::add,JsonArrayBuilder::add

), JsonArrayBuilder::build

));

@Delabassee @JosePaumard#Devoxx #SE84EE

Why is it important for Java EE?

Collect into JSON

Avaiblable through the JsonCollectors factory

// Tomorrow, with JSON-P 1.1JsonArray names =

contacts.getValuesAs(JsonObject.class).stream().filter(x -> "f".equals(x.getString("gender"))).map(x -> (x.getString("name"))).collect(

JsonCollectors.toJsonArray());

Parallelism

@Delabassee @JosePaumard#Devoxx #SE84EE

A warning on parallelism

All parallel operations (Streams, ConcurrentHashMap)

take place in the common ForkJoinPool

The common ForkJoinPool takes all the

available cores / CPUs

@Delabassee @JosePaumard#Devoxx #SE84EE

A warning on parallelism

All parallel operations (Streams, ConcurrentHashMap)

take place in the common ForkJoinPool

The common ForkJoinPool takes all the

available cores / CPUs

To preserve your Application Server:

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "1") ;

CompletableFuture

@Delabassee @JosePaumard#Devoxx #SE84EE

CompletableFuture

New addition to j.u.concurrent

Allow to chain asynchronous tasks

Use case: test the asynchronous calls in the Servlet API,

EJB, JAX-RS, …

@Delabassee @JosePaumard#Devoxx #SE84EE

Creation of an asynchronous task

The Jersey way to create an asynchronous call

@Path("/resource")public class AsyncResource {

@GETpublic void asyncGet(@Suspended final AsyncResponse asyncResponse) {

new Thread(new Runnable() {public void run() {

String result = longOperation();asyncResponse.resume(result);

}}).start();

}}

@Delabassee @JosePaumard#Devoxx #SE84EE

Creation of an asynchronous task

(let us fix this code with Java 8)

@Path("/resource")public class AsyncResource {

@GETpublic void asyncGet(@Suspended final AsyncResponse asyncResponse) {

executor.submit(() -> {String result = longOperation();asyncResponse.resume(result);

});}

}

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

We want to check if the result object

is passed to the resume() method of the asyncResponse

It is a very basic test, but tricky to write since we are in an

asynchronous world

We have mocks for that!

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

We can inject a mock AsyncResponse, even mock the result

Then verify the correct interaction:

But we need to verify this once the run() method has been

called…

Mockito.verify(mockAsyncResponse).resume(result);

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

This is where CompletionStage come to the rescue!

@Path("/resource")public class AsyncResource {

@Inject ExecutorService executor;

@GETpublic void asyncGet(@Suspended final AsyncResponse asyncResponse) {

executor.submit(() -> {String result = longOperation();asyncResponse.resume(result);

});}

}

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

@Path("/resource")public class AsyncResource {

@Inject ExecutorService executor;

@GETpublic void asyncGet(@Suspended final AsyncResponse asyncResponse) {

executeAsync(asyncResponse);}

public CompletableFuture<Void> executeAsync(final AsyncResponse asyncResponse) {return CompletableFuture.runAsync(() -> {

asyncResponse.resume(longOperation());}, executor);

}}

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

AsyncResource asyncResource = new AsyncResource();

asyncResource.executeAsync(mockAsyncResponse); // returns the CompletableFuture.thenRun(() -> { // then execute this Runnable

Mockito.verify(mockAsyncResponse).resume(result);}

);

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

Be careful of visibility issues

1) It’s better to run this in the same thread

2) Since the mocks are used and checked in this thread,

create them in this thread too

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

So the complete pattern becomes this one

1) First we create our mocks

String result = Mockito.mock(String.class);AsyncResponse response = Mockito.mock(AsyncResponse.class);

Runnable train = () -> Mockito.doReturn(result).when(response.longOperation());Runnable verify = () -> Mockito.verify(response).resume(result);

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

So the complete pattern becomes this one

2) Then we create the call & verify

Runnable callAndVerify = () -> {asyncResource.executeAsync(response).thenRun(verify);

}

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

So the complete pattern becomes this one

3) Then we create the task

ExecutorService executor = Executors.newSingleThreadExecutor();

AsynResource asyncResource = new AsyncResource();asyncResource.setExecutorService(executor);

CompletableFuture.runAsync(train, executor) // this trains our mocks.thenRun(callAndVerify); // this verifies our mocks

@Delabassee @JosePaumard#Devoxx #SE84EE

How to test it?

Since a CompletableFuture is also a Future, we can fail

with a timeout if the test does not complete fast enough

ExecutorService executor = Executors.newSingleThreadExecutor();

AsynResource asyncResource = new AsyncResource();asyncResource.setExecutorService(executor);

CompletableFuture.runAsync(train, executor) // this trains our mocks.thenRun(callAndVerify) // this verifies our mocks.get(10, TimeUnit.SECONDS);

@Delabassee @JosePaumard#Devoxx #SE84EE

Conclusion

Java 8 is not just about lambdas

There are also many new and very useful patterns

Ready to be used before becoming a lambda ninja!

Not covered:

- Collection framework

- Concurrency, Concurrent hashmap

- JavaScript on the JVM with Nashorn

- Security

@Delabassee @JosePaumard#SE84EE

Thank you!

@Delabassee @JosePaumard#SE84EE


Recommended