📜 ⬆️ ⬇️

Getting ready for Java 9. Review of the most interesting improvements.


This Wednesday, August 30, a meeting of JUG.ru with Oleg Shelayev , Developer Advocate at ZeroTurnaround, which makes JRebel and XRebel, took place at the office of Oracle. The topic of the meeting is the tools for creating multi-threaded programs in Java (from designing bicycles and starting streams with handles, to ForkJoinPool, green streams and transactional memory).


Of course, we asked which Java 9 features ZeroTurnaround considered most useful. As a result, got hold of the article that you are currently reading. Oleg published the original article on the RebelLabs blog , there are still many interesting things there.


So, let's start.


We've been waiting for Java 9, and now, the release is just around the corner. Hooray! It was not the easiest way, but nevertheless, even the most heated debates about the module system are slowly moving forward, and most of the participants agree. Most likely, the release will take place very soon, for example, September 21, 2017 .


In this post I will not dwell on a detailed discussion of the system of modules. Instead, we’ll talk about things that any developer can use: Java innovations and standard APIs.


Next will be a list of our favorite innovations in the Java 9 API. In principle, to understand the essence, just look at the code samples. But you can run JShell and independently all these examples, with your own eyes look at the results.


Start JShell, will I wait ... ready? Not yet? OK ... did? Still no? Yes, it takes time to start ... ok, it started, great! Getting started.


Factory methods for collections


One of the most anticipated features of Java 9 is the ability to make collection literals so that it is more convenient to write down the simplest cases. Joke, of course , we are talking about Java, we do not have literals, there are only static factory methods. However, now we can easily create a List , Map and Set using ready-made methods:


 jshell> List.of(1, 2, 3) $1 ==> [1, 2, 3] jshell> Set.of(1, 2) $2 ==> [2, 1] jshell> Map.of("hello", "world") $3 ==> {hello=world} 

This was made possible by the emergence of static methods in interfaces (Java 8), which were learned to use List , Map and Set .


As a result, an unbutable collection is created that is optimized for maximum performance. For example, List1 stores a value in a class field, which speeds up access to it.


 jshell> List.of(1).getClass() $4 ==> class java.util.ImmutableCollections$List1 

Streams


In the Stream API added a couple of very useful features. In particular, the dropWhile and takeWhile . As you might guess from the title, dropWhile throws out the elements from the beginning until the condition is met, and takeWhile takes the elements until the condition is met.


 jshell> IntStream.range(1, 10).dropWhile(x -> x < 5).forEach(System.out::println) 5 6 7 8 9 

The next useful addition is the iterate() method. It allows you to replace cycles with streams. It is necessary to transfer to it the initial value of the stream, the condition (when it is necessary to stop the iterations), and the transition function (exactly how the next element will be obtained).


 jshell> IntStream.iterate(0, x -> x < 3, x -> x + 1).forEach(System.out::println) 0 1 2 

If you suddenly wanted to do fixed-point calculations on streams, this dream can come true in Java 9.


Optional


If suddenly someone does not remember how to use them, we have an excellent cheat sheet . In Java 9, the or() method was finally added, which allows you to link different Optionals in one line, without going down to constant checks on isPresent() .


 public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) jshell> Optional.empty().or(() -> Optional.of("RebelLabs")) $5 ==> Optional[RebelLabs] 

Another good addition is the ability to convert Optional to a stream containing no more than one element. This is really useful if you want to use lazy streams. In the example below, you can see the difference with your own eyes. If you call map() on the Optional, the mapping will occur instantly, but not on the stream.


 jshell> Optional.of(1).map(x -> x * 3) $10 ==> Optional[3] jshell> Optional.of(1).stream().map(x -> x * 3) $11 ==> java.util.stream.ReferencePipeline$3@67b92f0a 

And finally, we have a method ifPresentOrElse . In Java 8, it was possible to define behavior only for the case when the value of Optional exists. In Java 9, it became possible to specify two different Runnables, defining what to do if a value exists and if it does not exist.


 jshell> Optional.empty().ifPresentOrElse(x -> System.out.println(x), () -> System.out.println("empty")); empty 

Completable future


Another piece of the API, which was well polished, was the class CompletableFuture . They added a couple of great things to it, allowing you to write even more correct multi-threaded code.


One of the coolest methods is copy() , which returns a non-mutable copy of this CompletableFuture . In the following example, we create a CompletableFuture , make a copy of it and check that the completion of the copy does not affect the original object. This is very, very useful when creating an asynchronous API that returns a CompletableFuture . Previously, it was necessary to suffer notably, making a situation where the client can complete the CompletableFuture returned from such an API. For now, simply calling the copy() method.


 jshell> CompletableFuture<String> future = new CompletableFuture<>() future ==> java.util.concurrent.CompletableFuture@35d176f7[Not completed] jshell> future.copy() $15 ==> java.util.concurrent.CompletableFuture@4973813a[Not completed] jshell> future.isDone() $17 ==> false jshell> $15.isDone() $18 ==> false jshell> $15.complete("JRebel") $19 ==> true jshell> $15.isDone() $20 ==> true jshell> future.isDone() $21 ==> false 

But the coolest thing is that the parental stop applies to all copies!


 jshell> CompletableFuture<String> future = new CompletableFuture<>() future ==> java.util.concurrent.CompletableFuture@4bbfb90a[Not completed] jshell> future.copy() $24 ==> java.util.concurrent.CompletableFuture@5a8806ef[Not completed] jshell> future.complete("XRebel") $25 ==> true jshell> $24.isDone() $26 ==> true 

In addition, finally they added timeouts. Work with asynchronous API, without the presence of built-in functions for working with timeouts, was very stressful. In Java 9, it became possible to accurately determine the way CompletableFuture completes, after the manual expiration of a specified period of time.


 jshell> CompletableFuture<String> future = new CompletableFuture<>() future ==> java.util.concurrent.CompletableFuture@67205a84[Not completed] jshell> future.completeOnTimeout("Isn't this amazing", 1, TimeUnit.SECONDS) $28 ==> java.util.concurrent.CompletableFuture@67205a84[Not completed, 1 dependents] jshell> future.isDone() $29 ==> true 

Process Management API


Before Java 9, process management was not as cross-platform as I would like to believe. Working with subprocesses used to be somewhat crooked, and now in Java 9 it was finally straightened out. Java 9 adds the ProcessHandle class, which provides an API for analyzing the current process, other processes found on a child, their child processes, and so on. Just look at the example:


 jshell> ProcessHandle current = ProcessHandle.current(); current ==> 6349 jshell> current.pid() $33 ==> 6349 jshell> current.info().\TAB arguments() command() commandLine() equals( getClass() hashCode() notify() notifyAll() startInstant() toString() totalCpuDuration() user() wait( jshell> current.info().command() $34 ==> Optional[/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/bin/java] 

Most likely, the most frequently used function will be to get the command line and arguments used to start the process, but the other features are also quite worthy of attention.


Another popular task that will be much more convenient to do in Java 9 is the launch of the code immediately after the process is completed. Java 9 suggests using a new method for this:


 CompletableFuture<Process> onExit() 

Specify what you want to do, and it just works. No more tears and unstable libraries of others.


Stackwalker


Rejoice, haters of exceptions! Now you can work with spectra without creating Exception objects. Welcome to StackWalker !


StackWalker allows you to StackWalker stack, filter it, and effectively do various other things. This example will pull the top 5 items out of the frame:


 jshell> StackWalker.getInstance().walk(s -> s.limit(5).collect(Collectors.toList())); $36 ==> [do_it$(java:36), jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(DirectExecutionControl.java:209), jdk.jshell/jdk.jshell.execution.RemoteExecutionControl.invoke(RemoteExecutionControl.java:116), jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(DirectExecutionControl.java:119), jdk.jshell/jdk.jshell.execution.ExecutionControlForwarder.processCommand(ExecutionControlForwarder.java:134)] 

Java language enhancements


Not only the API is improved, but the language itself. First, the _ (underscore) character is no longer a valid identifier. If for some reason you use it, you will have to switch to double underlining! (Hint: do not do this).


 jshell> int _ = 1 | Error: | as of release 9, '_' is a keyword, and may not be used as an identifier | int _ = 1 | ^ | Error: | reached end of file while parsing | int _ = 1 | ^ jshell> int __ = 1; __ ==> 1 

This is so that in the future it is possible to replace unnecessary (optional) parameters with an underscore when calling a function.


Interfaces also slightly improved. Interfaces in Java 9 can contain private methods. In Java 8, we were able to store some common logic in default methods. Now we can isolate common logic inside interfaces, without the need to create auxiliary classes.


Here is a small synthetic example:


 jshell> interface A { private int zero() { return 0;} default int one() { return zero() + 1;}} | created interface A 

And finally, the latest innovation. Now you can use effectively final variables in try-with-resources blocks. This simplifies the code, you no longer need to declare variables inside try . Just work with them in the try block, and it compiles.


 boolean a() throws Exception { Socket s = new Socket(); try (s) { } return s.isClosed(); } 

After the try block has been executed, all the AutoClosable mentioned there will close AutoClosable .


Conclusion


Hooray! We looked at a lot of things, and these are not all the innovations that appeared in Java 9. Nevertheless, the above things seem to us the most useful, and they will be used as soon as possible.


The release of Java 9 has been preparing for quite some time, and it’s time for all of us to understand how it will affect us. Now this is more pertinent than ever, given that the mode of working with clasthpath will remain unchanged, and the transition to Java 9 can be easy and painless. You can now download the finished assembly of Java 9 , deal with new APIs, try them out, and get ready for the upcoming bright future!


The authors


Oleg Shelaev is a Java developer and Developer Advocate in ZeroTurnaround. When not writing java agents or tests, writing to the RebelLabs blog or speaking at conferences. In his free time, he is trying to promote science at the University of Tartu, studying the problems of dynamic software updates.


')

Source: https://habr.com/ru/post/336864/


All Articles