What’s new in java 9 for developers

What’s new in java 9 for developers

Now that Java 9 is Features Complete, it’s time to look at all the new stuff that this new version will bring us, developers using java.

Of course, everybody have heard about the modularization of the JDK (project Jigsaw), a long awaiting project. Well, I’m not going to talk about it here! I will only speak about the new functionalities that target common developers, not the ones that target framework authors or advanced users.

First of all, the development of Java 9 was mainly made via a set of JEP (Java Enhancement Proposal, more info here) : http://openjdk.java.net/jeps/1) that we can found the list here : http://openjdk.java.net/projects/jdk9/. Of all these JEPs, I will talk about the ones that contains changes visible and usable in the everyday life of a developer.

JEP 102: Process API Updates

Managing from java the call to an external process has always been complicated. Especially if we want to do some operations that seems basic but not foreseen in the actual implementation (getting the PID, killing a process, gathering the command lines, …)

Via the JEP 102 : Process API Updates, the Process API have been greatly enhanced to allow all these information, on the process of the JVM (ProcessHandle.current()), or on a child process created by Runtime.getRuntime().exec(“your_cmd”). Moreover, like always with java, it’s compatible will all the supported OS (so with Windows AND Linux!).

Here are some usage examples in Java 9:

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

JEP 110: HTTP/2 Client (Incubator)

HTTP/2 is already out and a lot of websites already use it. So it is time for Java to offer a client implementation. In the mean time, the API has been revisited to offer a simpler implementation that the really old HttpURLConnection that was the only way to make HTTP request in Java in the JDK (and the reason why developers used third-party library like Apache HttpClient or OKHttp). With the JEP 110: HTTP/2 Client (Incubator) Java get an up-to-date HTTP client, synchronous or asynchronous (in this case, it is based on CompletableFuture).

Here is an example of an asynchronous usage :

/**
 * 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.
}

JEP 259: Stack-Walking API

Going through an execution stack in Java has never been an easy task … now it is one, thanks to the Stack-Walking API : http://openjdk.java.net/jeps/259

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

JEP 269: Convenience Factory Methods for Collections

The JEP 256 brings one of the biggest API change in Java 9 : static methods on the interfaces of the Collection API for easily create immutable collections. More info here : http://openjdk.java.net/jeps/269. This API targets the creation of small collections (list, set, map). Performance and memory utilization has been on the center of the implementation of these collections.

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

JEP 266: More Concurrency Updates

The JEP 266: More Concurrency Updates as it’s name didn’t indicate, contains one of the major evolution of Java 9 : an implementation of the Reactive Streams in Java via the Flow class. Java will then join the very hype group of reactive languages!

The class Flow contains three interfaces for the implementation of your reactive streams :

  • Publisher : Publish messages that the subscribers will consume. The only method is subscribe(Subscriber).
  • Subscriber : Subscribe to a publisher for receiving messages (via the method onNext(T)), error messages (onError(Throwable)), or a signal that there will be no more messages (onComplete()). Before anything else, the publisher needs to call  onSubscription(Subscription).
  • Subscription : The connection between a publisher and a subscriber. The subscriber will use it for asking for messages (request(long)) or cutting the connection (cancel()).

Here is an example from the tutorial available here :

public class MySubscriber<T> implements Subscriber<T> {  
  private Subscription subscription;  
  
  @Override  
  public void onSubscribe(Subscription subscription) {  
    this.subscription = subscription;  
    subscription.request(1); //a value of Long.MAX_VALUE may be considered as effectively unbounded  
  }  
  
  @Override  
  public void onNext(T item) {  
    System.out.println("Got : " + item);  
    subscription.request(1); //a value of Long.MAX_VALUE may be considered as effectively unbounded  
  }  
  
  @Override  
  public void onError(Throwable t) {  
    t.printStackTrace();  
  }  
  
  @Override  
  public void onComplete() {  
    System.out.println("Done");  
  }  
}  

And now the Publisher example :

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

Moreover, there as been some changes on the CompletabeFuture API (it’s more or less an equivalent to the JavaScript promises in Java) that allow, among other things, a better composition of the CompletableFuture between them :

  • copy():CompletableFuture
  • completeAsync​(Supplier< ? extends T> supplier):CompletableFuture
  • orTimeout​(long timeout,TimeUnit unit):CompletableFuture
  • completeOnTimeout​(T value, long timeout, TimeUnit unit):CompletableFuture
  • failedFuture​(Throwable ex):CompletableFuture

For a complete list of these new methods, see the once with Since 9” in the javadoc : http://download.java.net/java/jdk9/docs/api/java/util/concurrent/CompletableFuture.html

JEP 277: Enhanced Deprecation

The JEP 277: Enhanced Deprecation allow to give extra information on the deprecation via the annotation @Deprecated, two new attributes that allow developers to know if the deprecated API used is intended to be deleted some day and when the deprecation occurs. The purpose is to facilitate the lifecycle of applications and allow, maybe more easily, to delete some API on the JDK itself in the future.

Here is a small example that said that the MyDeprecatedClass is deprecated since version 9 and will be deprecated some days :

@Deprecated(since="9", forRemoval=true)
public class MyDeprecatedClass {
    //deprecated stuff
}

JEP 222: jshell: The Java Shell (Read-Eval-Print Loop)

A lot of languages (ruby, scala, python, …) have a Read-Evaluate-Print-Loop (REPL), a shell. This allow an easy learning of the language and give a direct access to the language from a simple shell. Whether it was for introducing the language, prototyping or testing, it’s always a good thing to have a shell and avoid the ceremonial of editing, compiling and packaging code.

With Java 9, born jshell, the java REPL! More info on the JEP : http://openjdk.java.net/jeps/222

From the command line, execute /bin/jshell and let you guide with the hep (/help). Example below :

jshell the Java REPL
jshell the Java REPL

An article that goes into more details : http://jakubdziworski.github.io/java/2016/07/31/jshell-getting-started-examples.html

JEP 213: Milling Project Coin

The Project Coin is a project of evolution of the language, started with Java 7, with the purpose of simplification of the usage of the language for the developers, by bringing small modifications in the order of “syntactic sugar”. The JEP213 : Milling Project Coin contains the implementation in Java 9 of the last parts of the project.

  • @SafeVarargs allowed on private method (previously only on static or final ones)
  • Allow the operator <> for abstract class (when the type is denotable)
  • Disallow ‘_’ as a valid identifier to allow it’s reuse in Java 10 (traditionally used to name an unused parameter that we don’t want to use when overloading a method)
  • Private methods in interfaces : allow code factorization in static methods (factorization of codes between two static methods in the same interface)
  • Allow final variables (or effectively final) in a try-with-resource (example bellow) :

Before Java 9: 

final Resource r = new Resource(); 
try (Resource r2 = r) { … }

In Java 9 :

final Resource r = new Resource(); 
try (r) { … // Cannot mutate r }

JEP 211 : Elide Deprecation Warnings on Import Statements

Before : importing a deprecated class generate a warning at compile time, after … no more warning. More info here : http://openjdk.java.net/jeps/211

A lot of other changes, outside any JEP :

Stream & Collectors:

  • Stream.takeWhile(Predicate< ? super T> predicate):Stream : build a stream that contains the element of the first one while the predicate is true, as soone as the predicate becomes false, the stream is stopped.
  • Stream.dropWhile(Predicate< ? super T> predicate):Stream : the opposite of takeWhile, build a stream that contains the first false elements then all the others. While the predicate is false : drop the elements, then, include them in the stream.
  • Stream.ofNullable(T element):Stream : return a stream with the element or an empty one if the element is null. Avoid using Optional with the streams.
  • Stream.iterate​(T, Predicate< ? super T>, UnaryOperator) : réplique une boucle for standard : Stream.iterate(0; i -> i<10, i -> i+1)
  • Collectors.filtering(Predicate< ? super T>,Collector< ? super T,A,R>) : execute a filter prior to the collector (see an example in the Javadoc that explain the differences between Stream.filter() before a collector)
  • Collectors.flatMapping​(Function< ? super T,? extends Stream>,Collector< ? super U,A,R>) : execute a flatMap operation prior to the collector (see an example in the Javadoc)
//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())
    ));

An article on this suject : http://www.baeldung.com/java-9-stream-api

Optional

4 new methodes have been added to the Optional class :

  • or(Supplier):Optional : return the same Optional or one build with the Supplier in parameter if there is no value. This allow a lazy construct of the other Optional is no value is provided.
  • ifPresent(Consumer):void : execute the Consumer in parameter if there is a value.
  • ifPresentOrElse(Consumer, Runnable):void : execute the Consumer in parameter if there is a value or execute the Runnable
  • stream():Stream : return a Stream of one element if there is a value or an empty Stream. This allow to use the power of the Stream API with 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"]

An article on this subject : http://www.baeldung.com/java-9-optional

Java Time :

Multiple addons on the Java Time API, among other things the possibility to create streams of dates with LocalDate.datesUntil(LocalDate) and LocalDate.datesUntil(LocalDate, Period).

More info here : http://blog.joda.org/2017/02/java-time-jsr-310-enhancements-java-9.html

Others :

  • InputStream.readAllBytes():byte[] : read in one time an input stream in a byte array
  • InputStream.readNBytes(byte[] b, int off, int len):int : read in one time an input stream in a byte array with offset and limit.
  • Objects.requireNonNullElse(T obj, T defaultObj) : return the first element if not null, otherwise the second. If both are null : NullPointerException !
  • Objects.requireNonNullElseGet(T obj, Supplier supplier)  : return the first element if not null, otherwise call supplier.get().
  • int Objects.checkIndex(int index, int length) : check the index : generate an IndexOutOfBoundsException if the index is less than 0 or more or equals to the size. This method might be optimized by the JVM.
  • int Objects.checkFromToIndex(int fromIndex, int toIndex, int length) : the same but for the sub-range fromIndex/toIndex
  • int Objects.checkFromIndexSize(int fromIndex, int size, int length) : the same but for the sub-range fromIndex/fromIndex + size
  • {Math, StrictMath}.fma() : implementation of a fused-multiply-accumulate (fma)
  • {Math, StrictMath}.{multiplyExact, floorDiv, floorMod}
  • {BigDecimal, BigInteger}. sqrt() : square root
  • Arrays.equals(), Arrays.compare(), Arrays.compareUnsigned(), Arrays.mismatch( : a lot of new methods to compare arrays with a lot variations : signed, unsigned,
    equality, mismatch, with from/to index, …

Performance :

The following JEPs are focused on the performance of the JVM, I will not introduce them in details here (but probably in a next article), here is the list :

  • JEP 143: Improve Contended Locking : optimization of Java monitors (locks).
  • JEP 193: Variable Handles : C++ atomics …
  • JEP 197: Segmented Code Cache : the code cache (a part of the Metaspace) has been segmented to optimize the performances.
  • JEP 254: Compact Strings : enhancement of the String implementation in Java to allow a more compact version in case of ISO-8859-1 (or Latin-1) strings. String in Java was stored by defaults in UTF-16 : each character was stored on two bytes. Now, when the string will be created, if it’s compatible with ISO-8859-1 it will be stored on one byte only.
  • JEP 274: Enhanced Method Handles : several addons to the MethodHandle API
  • JEP 280: Indify String Concatenation : intrasification of the concatenation of the strings on the JVM. Multiple concatenation strategies has been implemented, including one based on Method Handles (with StringBuilder or inline), this is the default one.
  • JEP 285: Spin-Wait Hints : for low level (power) users only : this ability to give a hint to the JVM that the application is in a spin-wait-loop …

Links :

Here are the articles that inspires me to write this one :

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

One thought on “What’s new in java 9 for developers

  1. Article très intéressant, j’ai vu pas mal de choses que je n’avais pas vu ailleurs dans d’autres articles “What’s new in Java 9…”

    Pour infos mes features préférées sont :
    * Factory Methods for Collections (hier encore je galérais à initialiser une Map statique et immutable…)
    * Les nouvelles méthodes de stream (surtout takeWhile et dropWhile, mais les autres aussi)
    * ifPresentOrElse de l’Optional
    * InputStream.readAllBytes[], que je ne connaissais pas, tellement pratique !

    J’ai pu tetser un peu Jshell, je n’étais pas convaincu, je trouve que ce n’était pas le même feeling qu’en Scala ou en Clojure. Par contre, ça peut être pratique pour tester un truc du langage dont on est pas certain.

    J’ai hâte de voir venir le pattern matching et les collections immutables quand même. Après, il ne manquera plus que le syntaxic sugar pour initialiser les maps et ça sera parfait !

    Petit tips pour finir :
    Tu peux transformer ‘Arrays.asList(items).stream()’ en ‘Arrays.stream(items)’ si items est un tableau. Ca évite le passage par une collection supplémentaire.

    Alex

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.