Pour les développeurs
Loïc Mathieu - @loicmathieu
Project Jigsaw
// 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();
/**
* The HTTP API functions asynchronously and synchronously.
* In asynchronous mode, work is done in threads (ExecutorService).
*/
public static void main(String[] args) throws Exception {
HttpClient.getDefault()
.request(URI.create("http://www.loicmathieu.fr"))
.GET()
.responseAsync() // CompletableFuture
.thenAccept(httpResponse ->
System.out.println(httpResponse.body(HttpResponse.asString()))
);
Thread.sleep(999); // Give worker thread some time.
}
Stack-Walking API : une nouvelle API pour parcourir une stack d'execution.
// return class/method only for our classes.
private static List<String> walkAndFilterStackframe() {
return StackWalker.getInstance().walk(s ->
s.map( frame -> frame.getClassName() + "/" + frame.getMethodName())
.filter(name -> name.startsWith("fr.loicmathieu"))
.limit(10)
.collect(Collectors.toList()) );
}
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). Exemple ci-dessous :
Project Coin est un projet d’évolution du language, qui a débuté avec java 7 dans le but de simplifier l’utilisation du language pour les développeurs en apportant des petites modifications de l’ordre du « sucre syntaxique ».
La JEP213 : Milling Project Coin contient l’implémentation dans Java 9 des dernières partie du projet.
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)
Beaucoup de nouvelles méthodes permettant de comparer des tableaux :
Arrays.equals()
Arrays.compare()
Arrays.compareUnsigned()
Arrays.mismatch()
Voici une liste de JEP de Java 9 axés performances :
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 a potentiellement ralenti le démarrage de java 9 : attention test réalisé sur une version non définitive de Java 9 !
Des tests réalisés en comparaison d'un Java 9EAb176 et d'un Java 8u144 ont montré que :
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
public class HelloWorldLambda {
public static void main(String[] args) {
Runnable hello = () -> System.out.println("Hello lambda world");
hello.run();
}
}
Les tests en détails : http://www.loicmathieu.fr/wordpress/informatique/demarrage-jvm-8-vs-9/
time java HelloWorld
real 0m0.085s
user 0m0.078s
sys 0m0.019s
time java HelloWorldLambda
real 0m0.185s
user 0m0.236s
sys 0m0.032s
java -XX:+UnlockDiagnosticVMOptions \
-XX:NativeMemoryTracking=summary \
-XX:+PrintNMTStatistics \
-Xmx16m -Xms16m HelloWorld
Total: reserved=1356124KB, committed=57156KB
java -XX:+UnlockDiagnosticVMOptions \
-XX:NativeMemoryTracking=summary \
-XX:+PrintNMTStatistics \
-Xmx16m -Xms16m HelloWorldLambda
Total: reserved=1358869KB, committed=59901KB
time java HelloWorld
real 0m0.161s
user 0m0.177s
sys 0m0.048s
time java HelloWorldLambda
real 0m0.199s
user 0m0.228s
sys 0m0.042s
java -XX:+UnlockDiagnosticVMOptions \
-XX:NativeMemoryTracking=summary \
-XX:+PrintNMTStatistics \
-Xmx16m -Xms16m HelloWorld
Total: reserved=1389612KB, committed=97536KB
java -XX:+UnlockDiagnosticVMOptions \
-XX:NativeMemoryTracking=summary \
-XX:+PrintNMTStatistics \
-Xmx16m -Xms16m HelloWorldLambda
Total: reserved=1390008KB, committed=98188KB
Cette présentation est inspirée de l'article :
http://www.loicmathieu.fr/wordpress/informatique/les-nouveautes-de-java-9-pour-les-developeurs/
Cet article est lui-même inspiré de :
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