What to expect from Java in 2020?

8 min


2020 is already in full swing, let’s discuss what changes in the Java world await us this year. This article will list the main trends of Java and JDK. And I will be happy with the additions from readers in the comments.

Immediately make a reservation that the article is more of a fact-finding character. Details on each topic discussed can be found on the website of the corresponding project or in publications in open sources.

image


So, let’s begin. Unfortunately, you will immediately have to disappoint those who do not follow the Java release cycle too much, but who are waiting for a long support program (LTS). This year we are waiting for releases with only a short support life cycle (STS).
The first we will consider the upcoming release of JDK 14, which should be released in mid-March. In this release cycle, as many as 16 JEPs are claimed. Here is the complete list:

305: Pattern Matching for instanceof (Preview)
343: Packaging Tool (Incubator)
345: NUMA-Aware Memory Allocation for G1
349: JFR Event Streaming
352: Non-Volatile Mapped Byte Buffers
358: Helpful NullPointerExceptions
359: Records (Preview)
361: Switch Expressions (Standard)
362: Deprecate the Solaris and SPARC Ports
363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector
364: ZGC on macOS
365: ZGC on Windows
366: Deprecate the ParallelScavenge + SerialOld GC Combination
367: Remove the Pack200 Tools and API
368: Text Blocks (Second Preview)
370: Foreign-Memory Access API (Incubator)

Many JEPs from this list were widely covered at the Joker 2019 conference. I will focus on those that seem to me the most interesting.

Pattern Matching for instanceof (Preview)

The long JEP is finally coming out in Preview. I think if you are a practicing programmer who has been writing Java code for many years, then you have come across this pain more than once:

if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.toUpperCase());
}

If you wrote or are writing code also in Kotlin, then the pain from seeing the Java code is a little worse. Amber project participants will present us with their vision of Pattern Matching in Java, which should reduce this pain. With the advent of Java 14, we can rewrite the example as follows:

if (obj instanceof String s) {
   System.out.println(s.toUpperCase());
}

It seems that the add-on is not so valuable – we save a line of code. But suppose we want to do the following:

if (obj instanceof String) {
    String s = (String) obj;
    if (s.contains(“prefix_”)) {
       return s.toUpperCase();
    }
}
return null;

It looks bulky, doesn’t it? Let’s try the same thing, but with Pattern Matching.

return (obj instanceof String s) && s.contains(“prefix_”) ? s.toUpperCase() : null;

So obviously it will be better. But remember that the status of this functionality is Preview. Let’s see what changes over time. For me, it will definitely make my life better.

Helpful NullPointerExceptions

2020 is in the yard, and you still write so that NullPointerExceptions fly out for you? Don’t worry, you’re probably not the only one. Goetz Lindenmaier and Ralf Schmelter did not suggest a new way to get away from NullPointerExceptions (Optional is still with us), but they proposed improving the debugging process of the application to understand exactly where null lies. So, let’s imagine that we write the code at five o’clock … at night, of course. And we wrote this function:

public String getStreetFromRequest(Request request) {
   return request.getAddress().getStreet().toUpperCase();
}

Not bad, but they completely forgot to put @Nullable and @Nonnull annotations and check for the address in the transmitted fields. Got a NullPointerException. What does the exception tell us?

Exception in thread "main" java.lang.NullPointerException
	at Program.getStreetFromRequest(Program.java:10)
	at Program.main(Program.java:6)

Alas, we see only the row, class and stack. Where exactly did null return to? Maybe this is a request? Maybe getAddress () returned null? Or maybe getStreet ()? Well, call chains sometimes hurt.

The JEP authors propose a solution: when throwing an exception, it is supposed to go around the stack to determine where exactly null returned, and then display the name of the variables / methods. Let’s try Java 14 with the -XX: + ShowCodeDetailsInExceptionMessages option. We start and get a little different:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toUpperCase()" because the return value of "Address.getStreet()" is null
	at Program.getStreetFromRequest(Program.java:10)
	at Program.main(Program.java:6)

Now we know that night programming does not bring to good (but sometimes leads to the completion of tasks on time), and in our program we forgot that the address is not a required field.

Records (Preview)

Still generating getters / setters / equals / hashCode with idea? Then this JEP is coming to you!
Data classes are far from the last place in the life of an application software developer. Each time we have to either generate methods of Data classes using our favorite IDE, or use various compile-time plugins to generate the necessary methods, such as lombok.
As a result, we have a lot of code similar to this:

public class Request {
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
       this.address = address;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Request request = (Request) o;
        return Objects.equals(address, request.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(address);
    }

    @Override
    public String toString() {
        return "Request{" +
                "address=" + address +
                '}';
    }
}

Or such:

@Data
@AllArgsConstructor
public class Request {
    private Address address;
}

In Java 14, members of the Amber project propose a new syntax for creating data classes. To do this, use the new keyword record. The syntax for Record is slightly different than for describing classes or enum, and is slightly similar to Kotlin. The code above can be rewritten as follows:

public record Request(Address address) {
}

All record fields have private and final modifiers by default. The record itself is a final class and cannot be inherited from another class, but it can implement interfaces. In the record classes from the box we get: getters methods, a public constructor, the parameters of which are all record fields in the description order, equals / hashCode and toString. From the unpleasant: we cannot add fields to the record, except for those specified after the class name. For example, this code will result in an error:

public record Request(Address address) {
   private final String anotherParameter; // compilation error
}

Text Blocks (Second Preview)

Text blocks were released as previews back in Java 13. We users twisted, rotated and gave feedback (I sincerely believe that you are already using Java 13 with preview). As a result, the Java creators made minor changes to textblocks. First, we can now explicitly indicate where the line ends, by putting escapesequence s in our line. Here is an example:

public static void main(String[] args) {
        final var test = """
                This is the long text block with escape string s
                that is really well done            s
                """;
        System.out.println(test);
}

Now we explicitly set all spaces to the s character and all space characters will be saved to the s character.
Secondly, now we can wrap long lines of a text block without receiving n characters in the final line. To do this, we only need to add at the line break. What does it look like:

public static void main(String[] args) {
        final var test = """
                This is the long text block with escape string 
                that is really well-done functional            
                """;
System.out.println(test);

After execution, we get the following line: “This is the long text block with escape string that is really well-done functional”.
A good addition, it seems to me. I really look forward to translating this functionality into standard.
All the features that we reviewed are likely to be widely discussed at upcoming conferences. Some of them have already been discussed at Joker 2019. Be sure to check out the Joker 2019 talk on this topic “Feature evolution in Java 13 and beyond” by Cay Horstmann.

And some more interesting things.

There are two interesting items on the JEP list in the incubator. To begin with, we will have a universal tool that will create installers for different operating systems (well, finally, I want to tell those who danced around installing programs on Windows). Jpacker will be able to create msi / exe installers for Windows, packages for macOS and rpm / deb for Linux. Let’s see what happens, but in those rare cases when I did something for desktop, I personally suffered from the fact that I did not have a regular tool for assembling the installer.
Even more promising is the new API for accessing “Foreign-Memory”, i.e. any kind of native or persistent memory. This API is primarily useful for Java database creators or framework creators such as, for example, Netty. They, using Unsafe and ByteBuffer, optimize memory access with off-heap as much as possible.

Next release. Joy and disappointment.

In September, we are waiting for another short-term support release at number 15. The list of JEPs that will be included in the final release is still open. So far, you can see a lot of different changes in the language itself, in the standard library and virtual machine.
Here is the list of candidates (it can change quickly; we’re looking at it here: bugs.openjdk.java.net/secure/Dashboard.jspa?selectPageId=19114):

111: Additional Unicode Constructs for Regular Expressions
116: Extended Validation SSL Certificates
134: Intuitive Semantics for Nested Reference Objects
152: Crypto Operations with Network HSMs
198: Light-Weight JSON API
218: Generics over Primitive Types
300: Augment Use-Site Variance with Declaration-Site Defaults
301: Enhanced enums
302: Lambda leftovers
303: Intrinsics for the LDC and INVOKEDYNAMIC Instructions
306: Restore Always-Strict Floating-Point Semantics
338: Vector API (Incubator)
339: Compiler Intrinsics for Java SE APIs
348: Compiler Intrinsics for Java SE APIs
356: Enhanced Pseudo-Random Number Generators
360: Sealed Types (Preview)
371: Hidden classes

As you can see, the list still does not have much expected things. First of all for me it is Project Loom. The idea of ​​structural parallelism has been very popular in recent years. Coroutines can greatly simplify the task of competitive parallel computing and asynchronous execution of tasks. Great examples of implementing this idea can be seen, for example, in the languages ​​Kotlin (coroutines) and Go (goroutines). Java is also exploring the idea of ​​structural parallelism, and there are already first results. For now, you can see them only by collecting the JDK from the project repository.
A very promising project Valhalla also has not pleased us with any previews. An interesting report on this project was presented at Joker 2019 (“Do Java require“ inline ”types? A narrow view of the performance engineer on Valhalla project” by Sergey Kuksenko).

What is presented in the list?
The first thing that catches your eye is the JSON API. The question immediately arises – why? There is clearly no definite answer. The JEP section on motivation says that JSON has become something of a standard for web services, and now it’s time to adapt Java SE to interact with JSON (even though there are a ton of libraries for parsing JSON now). The most likely explanation is the ability for software developers to use a small core API to reduce the size of the bundle without having to drag the heavy Jackson to themselves. I do not see any other explanation, because it will not even have databinding.

We also see a number of improvements related to the cryptographic API. To get started, JDK developers want to expand the process of validating SSL certificates by adding support for EVSSL certificates. Using this API in Java, you can determine whether an SSL connection is trusted by an EV certificate (Extended Validation). The EVSSL certificate in accordance with the guideline will be fully supported. A new EdDSA cryptographic algorithm will also be added and verification of HSM cryptography will be improved.

From language things, I would single out the implementation of Generics on primitives. Everyone who has ever programmed in C # and switched to Java, probably could ask the question, why can’t you do Generic types on primitives. The answer is simple – Generics only work with objects, and primitives are not objects and, in particular, do not inherit an Object class. This is not the first year that a war has been waged on this issue, and Brian Goetz is returning to it again. There is nothing special to describe so far. The task is clear – to support constructs such as List. But even at the moment there are 13 open questions that need to be solved before implementing this functionality. Honestly, I wonder how this series will end.

And the last thing I want to touch on is the sealed types. This is the next step towards pattern matching. Sealed Types is a language extension that implements the sealed (modifier) ​​and permits keywords for a class or interface.
Using the sealed class, we limit the number of descendants to only those classes that are specified in permits (an explicit restriction) or in the same compilation unit (file). An example description of a sealed class:

// неявно
public abstract sealed class Base {
   public static class ChildA extends Base{}
   public static class ChildB extends Base{}
}

// явно
public sealed interface BaseInterface permits ChildC, ChildD{
}

//в другом файле
public class ChildC implements BaseInterface {
}
//в другом файле
public class ChildD implements BaseInterface {
}

The sealed modifier ensures that only a limited finite set of descendants can extend the base class or implement an interface. This property can be used when processing objects of these classes. And, of course, this is a great candidate for use in a switch statement with pattern matching.

Conclusion

We looked at the various JDK innovations this year. Some of them will shoot, some not. But most of all in the new JDKs, I expect new small (or not so) optimizations that make our programs faster for free with every release. And if you were at the last Joker 2019 and visited the report of Tagir Valeev Java 9-14: Small optimizations, then most likely, like me, you were impressed by the work that contributors do to optimize JDK. Its results are not visible at first glance and are not reflected in more than one JEP, but we use them every day.
Good Java releases to us all. Explore new platform features, go to conferences and follow trends.


0 Comments

Leave a Reply