Pour les développeurs
Loïc Mathieu - @loicmathieu
Jusqu'à Java 9 : fonctionnement en features release :
Ceci à mener à :
Depuis Java 10 : fonctionnement en release train :
Ceci à mener à :
Depuis Java 10 on a donc une release tous les 6 mois.
Toutes les 6 releases on va avoir une release Long Term Support -- LTS.
La politique de support gratuit a changé :
Pas de panique, d'autres proposent du support étendu gratuit :)
Source : Java Developer Survey 2018 (10500 répondants)
Source: NodeJS user survey 2018 (1650 répondants)
OpenJDK est le projet open source d'implémentation du language Java et de la JVM.
Beaucoup d'organisations participent à ce projet.
Oracle est une de ces organisations (la principale).
Depuis Java 11, Oracle fournit deux distributions d'OpenJDK qui sont identiques en terme de fonctionnalités :
Il existe beaucoup d'autres distributions de Java, dont certaines proposent déjà un support plus étendu qu'OpenJDK :
Source: Java Developer Survey 2018
Java a été modularisé : un système de module a été créé et le JDK lui-même a été découpé en plusieurs modules.
Chaque module définit les services qu'il expose et les modules qu'il utilise : ceci permet d'avoir une vue clair des dépendances des différents modules entre-eux.
Les API internes sont dorénavant dans des modules internal non accessible.
On peut créer une image native de notre application contenant uniquement les modules nécessaire via jlink.
// Get PIDs of own processes
System.out.println("Your pid is " + ProcessHandle.current().getPid());
//start a new process and get PID
Process p = Runtime.getRuntime().exec("sleep 1h");
ProcessHandle h = ProcessHandle.of(p.getPid()).orElseThrow(IllegalStateException::new);
// Do things on exiting process : CompletableFuture !
h.onExit().thenRun( () -> System.out.println("Sleeper exited") );
// Get info on process : return Optional!
System.out.printf("[%d] %s - %s\n", h.getPid(), h.info().user().orElse("unknown"),
h.info().commandLine().orElse("none"));
// Kill a process
h.destroy();
List<Integer> listOfNumbers = List.of(1, 2, 3, 4, 5);
Set<Integer> setOfNumbers = Set.of(1, 2, 3, 4, 5);
Map<String, String> mapOfString =
Map.of("key1", "value1", "key2", "value2");
Map<String, String> moreMapOfString =
Map.ofEntries(
Map.entry("key1", "value1"),
Map.entry("key2", "value2"),
Map.entry("key1", "value3")
);
Implémentation des Reactive Stream en Java via la classe Flow :
public class MySubscriber<T> implements Subscriber<T> {
private Subscription subscription;
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
subscription.request(1);
}
@Override
public void onNext(T item) {
System.out.println("Got : " + item);
subscription.request(1);
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("Done");
}
}
//Create Publisher
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
//Register Subscriber
MySubscriber<String> subscriber = new MySubscriber<>();
publisher.subscribe(subscriber);
//Publish items
System.out.println("Publishing Items...");
String[] items = {"1", "x", "2", "x", "3", "x"};
Arrays.asList(items).stream().forEach(i -> publisher.submit(i));
publisher.close();
Quelques changements à l’API CompletableFuture ont vu le jour permettant, entre autre, une meilleur composition des CompletableFuture entre elles :
copy():CompletableFuture<T>
completeAsync(Supplier<? extends T> supplier):CompletableFuture<T>
orTimeout(long timeout,TimeUnit unit):CompletableFuture<T>
completeOnTimeout(T value, long timeout, TimeUnit unit):CompletableFuture<T>
failedFuture(Throwable ex):CompletableFuture<T>
Ajout de deux attributs à l'annotation @Deprecated :
Le but est de faciliter le cycle de vie des applications et de permettre, peut-être plus sereinement, de supprimer dans le futur certaines API du JDK lui-même.
@Deprecated(since="9", forRemoval=true)
public class MyDeprecatedClass {
//deprecated stuff
}
Beaucoup de languages (ruby, scala, python, …) proposent une Read-Evaluate-Print-Loop (REPL), un shell.
Celà permet un apprentissage aisé du language et donne une porte d’entré direct depuis un simple shell.
Eviter le cérémonial d’édition, de compilation, de packaging du code.
Avec Java 9, apparait jshell, le REPL de java !
Depuis une ligne de commande, exécutez <java_home>/bin/jshell et laissez vous guider par l’aide (/help).
Avant Java 9 :
final Resource r = new Resource();
try (Resource r2 = r) { … }
Après Java 9 :
final Resource r = new Resource();
try (r) { … // Cannot mutate r }
//iterate
/java 8 style : using for loop
for (int i = 0; i < 10; ++i) {
System.out.println(i);
}
//java 9 style, using Stream.iterate
Stream.iterate(0, i -> i < 10, i -> i + 1).forEach(System.out::println);
//takeWhile and dropWhile
Stream<String> stream = Stream.iterate("", s -> s + "s")
stream.takeWhile(s -> s.length() < 10);
stream.dropWhile(s -> !s.contains("sssss"));
//ofNullable : returning Stream.empty() for null element
//java 8 style : we need to make a check to know if it's null or not
collection.stream()
.flatMap(s -> {
Integer temp = map.get(s);
return temp != null ? Stream.of(temp) : Stream.empty();
})
.collect(Collectors.toList());
//java 9 style
collection.stream().flatMap(s -> Stream.ofNullable(map.get(s))).collect(Collectors.toList());
List<Integer> numbers = List.of(1, 2, 3, 5, 5);
Map<Integer, Long> result = numbers.stream()
.filter(val -> val > 3)
.collect(Collectors.groupingBy(i ->; i, Collectors.counting()));
result = numbers.stream()
.collect(Collectors.groupingBy(i -> i,
Collectors.filtering(val -> val > 3, Collectors.counting())
));
4 nouvelles méthodes ont été ajoutée à la classe Optional :
//Optional.or : a lazy version of orElse
Optional<String> value = ...;
Optional<String> defaultValue = Optional.of(() -> bigComputation());
return value.or(defaultValue);//bigComputation will be called only if value is empty
//Optional.ifPresent :
Optional<String> value = ...;
AtomicInteger successCounter = new AtomicInteger(0);
value.ifPresent(
v -> successCounter.incrementAndGet());
//Optional.ifPresentOrElse :
Optional<String> value = ...;
AtomicInteger successCounter = new AtomicInteger(0);
AtomicInteger onEmptyOptionalCounter = new AtomicInteger(0);
value.ifPresentOrElse(
v -> successCounter.incrementAndGet(),
onEmptyOptionalCounter::incrementAndGet);
//Optional.stream : unify the stream and Optional API
Optional<String> value = Optional.of("a");
List<String> collect = value.stream().map(String::toUpperCase).collect(Collectors.toList());
//["A"]
Plusieurs ajouts à l’API Java Time, entre autre la possibilité de créer un Stream de date avec :
LocalDate.datesUntil(LocalDate)
LocalDate.datesUntil(LocalDate,Period)
Les méthodes check[From]Index* 'peuvent' être optimisée par la JVM !
Beaucoup de nouvelles méthodes permettant de comparer des tableaux :
Arrays.equals()
Arrays.compare()
Arrays.compareUnsigned()
Arrays.mismatch()
C’est LA grande nouveauté de Java 10 : la possibilité d’utiliser le mot clé var à la place d’une déclaration standard de variable, à l’intérieur d’une méthode (variable locale) quand le type peut être inféré par le compilateur.
Var peut être aussi utilisé dans la déclaration des boucles for et du try-with-resource.
En Java 9 :
En Java 10 avec le mot clé var :
MyComplexType obj = new MyComplexType();
Map<String,List<MyComplexType>> map = new HashMap<String,List<MyComplexType>>();
var obj = new MyComplexType();
var map = new HashMap<String,List<MyComplexType>>();
Possible aussi dans les boucles et le try-with-resource
L’API Collection a été enrichie de méthodes statiques permettant la copie de collection existantes :
Dans les trois cas la collection retournée sera une collection immuable.
Dans la même mouvance que le précédent changement, les collectors de l’API Stream ont été enrichit pour permettre la création de collections immuable :
Optional.orElseThrow() est maintenant la manière privilégiée (au détriment de Optional.get()) pour récupérer un élément dans un Optional.
Son nom fait clairement référence au fait que si il n’y a pas d’élément, une exception sera lancée (ce qui est le cas pour Optional.get() mais souvent oublié par les développeurs l’utilisant).
Un nouvelle méthode à la classe Reader de directement transférer tout les caractère d’un Reader à un Writer :
Reader reader = new FileReader("from.txt");
Writer writer = new FileWriter("to.txt");
reader.transferTo(writer);
G1 est depuis Java 9 l’algorithme de Garbage Collection par défaut. Hors dans celui-ci, quand le collector n’arrive plus à nettoyer assez rapidement la heap de manière concurrente, il déclenche un Full GC qui était mono-threadé.
Depuis Java 10 l’implémentation de celui-ci a été changé en multi-threadé, le nombre de threads étant définit par -XX:ParallelGCThreads
Permet l’utilisation du mot clé var dans les signatures des lambdas.
But : permettre d'ajouter des modificateurs (ex: annotations) sans nécessité de mettre le type.
//avant Java 11
(@NotNull Foo<String> f, @Nullable Bar<String> b) -> s.process(b);
//après Java 11
(@NotNull var f, @Nullable var b) -> s.process(b);
//init a client
HttpClient httpClient = HttpClient.newBuilder()
.version(Version.HTTP_2) // this is the default
.build();
//create a request
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://http2.github.io/"))
.GET() // this is the default
.build();
//send the request and access the response
HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
logger.info("Response status code: " + response.statusCode());
logger.info("Response headers: " + response.headers());
logger.info("Response body: " + response.body());
//send asynchronously : return a ComparableFuture
httpClient.sendAsync(request, BodyHandlers.ofString())
.thenAccept(response -> {
logger.info("Response status code: " + response.statusCode());
logger.info("Response headers: " + response.headers());
logger.info("Response body: " + response.body());
});
A No-Op Garbage Collector !
A Scalable Low-Latency Garbage Collector
Beaucoup d’optimisation réalisé au sein de G1
Selon l’auteur : en passant de Java 8 à Java 11, on aurait
Des pauses 60% plus basse « gratuitement » pour une utilisation mémoire grandement réduite.
Beaucoup de travail a été fait pour optimiser le démarrage de Java en terme de temps de démarrage de la JVM et d'empreinte mémoire mené par Claes Redestad (Oracle).
L'implémentation de la modularisation et le passage au G1 GC a impacté le temps de démarrage d'une application, les optimisations réalisé dans les version 9, 10 et 11 permettent donc de contrebalancer ça.
Une JVM démarre en 80ms.
AppCDS ou jlink permettent de démarrer en quelques ms!
OpenJDK Startup From 8 Through 11
https://cl4es.github.io/2018/11/29/OpenJDK-Startup-From-8-Through-11.html
//new switch synthax : inspired by lambda
switch (day) {
case SATURDAY, SUNDAY -> {
System.out.println("Weekend !!!");
System.out.println("This is awesome ;)");
break;
}
default -> {
System.out.println("Default");
System.out.println("OK OK");
break;
}
}
//new switch synthax : implicit break and no default as all cases are covered
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
// switch expression using the new synthax : it returns a value !
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
//somethimes we need multiple lines : don't forget to break the result ;)
int j = switch (day) {
case MONDAY -> 0;
case TUESDAY -> 1;
default -> {
int k = day.toString().length();
int result = f(k);
break result;
}
};
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC.
Ces articles sont eux-même inspirés de ceux-ci :
https://blogs.oracle.com/darcy/resource/Devoxx/DevoxxUS-2017-jdk9-lang-tools-libs.pdf
http://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUID-BA9D8AF6-E706-4327-8909-F6747B8F35C5
http://blog.takipi.com/5-features-in-java-9-that-will-change-how-you-develop-software-and-2-that-wont/
https://bentolor.github.io/java9-in-action
http://www.javaworld.com/article/2598480/core-java/why-developers-should-get-excited-about-java-9.html
https://www.sitepoint.com/ultimate-guide-to-java-9/
http://www.javamagazine.mozaicreader.com/JulyAug2017
&
Loïc Mathieu - @loicmathieu
Un petit dojo est dispo ici : https://github.com/loicmathieu/dojo-java-9-10-11