Coming Up for Air

Java 15: New and Notable

JDK 15 hit General Availability today. While I spend most of my time in Kotlin these days, I do keep a close on Java, as it still has a special place in my heart, so I thought I’d make a quick post highlighting some of its new features. :) There are quite a few changes in the release, so I’ll list all of them, but focus on the ones I think most developers will find more interesting.

General Notes

There are some pretty techincal changes here (it seems to me) that most people won’t care about. If you’re into crypto, the EdDSA change might be of interest,. If you’re performance-sensitive, ZGC will likely pique your interest, and if you’re a framework developer, hidden classes sound pretty awesome. Solaris, RMI, and Javascript users, though, may be in for a slight disappointment, but these changes were telegraphed long ago, so they shouldn’t come as a surprise.

For my money, the most interesting (read as: applicable to me) are

  • Sealed classes

  • Pattern matching instanceof

  • Text blocks

  • Records

Let’s take a super quick looks.

Sealed Classes

There’s a good chance that at some point in your career, you’ve needed to define a hierarchy of classes and control where it can be extended. In languages like Kotlin, there is the sealed modifier that prevents the class from being extended without permission, so to speak. In Java however, you’re carefully curated list of system status codes, say, can be extended willy nill by any and all. Until now. the new feature, for those not familiar with the concept, allows the developer to "seal" a class, preventing its extension by all except a special few. In it’s simplest form, it might look like this:

abstract sealed class Shape {
    abstract public draw();
}

final class Square extends Shape {
    public draw() {
    }
}

final class Circle extends Shape {
    public draw() {
    }
}

In this example, Shape is abstract (though it need not be), and there are only two available shapes: Square and Circle. In this example, all three classes are declared in the same file, but, unlike, say, Kotlin, that need not be the case. If your classes are complex, have a lot of code, etc., and it would be better from a maintainability perspective, say, to have them in separate files, the compiler will let you do that, but you have to tell it which classes are allowed to participate:

public abstract sealed class Shape
    permits fully.qualified.class.Square,
            fully.qualified.class.in.another.package.Circle {
        ...
    }

Interfaces can also be sealed, with all of the same rules applying.

Pattern-matching instanceof (Preview feature)

For years, we’ve used instanceof to test the type of a variable, and for years, immediately after, we’ve type-casted that variable so we can use it:

if (foo instanceof Interface1) {
    ((Interface1)foo).someMethod();
}

Having to type (har har) twice was a bit annoying. JDK 15 brings a new syntax that lets us reduce that:

if (foo instanceof Interface1 f) {
    f.someMethod();
} else {
    f.someOtherMethod(); // compiler error
}

Notice that we can declare a variable after the instanceof check that we can then use in the true branch of the if. The variable is not available in the else.

This does not currently work in a switch statement, but that change is expected to come as well. This is only a preview feature so we can kick its tires, so use it with caution.

Text blocks

One of the things I’ve loved about Kotlin is the ability to write multi-line strings and let the compiler do the hardwork for me. For example.

val foo = """
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus
    finibus velit dictum lacinia.
    """.trimIndent()

This allows us to write a text block, spanning lines, and the system does the work for us to make a single, properly formatted string. In Java, that might look like

String foo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus\n" +
    "finibus velit dictum lacinia.";

JDK 15 allows this:

String foo = """
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus
    finibus velit dictum lacinia.
    """;

Very neat and clean.

Records

Finally, we come to records.In a nutshell, Records, a new kind of class on the JVM, allow us to declare an new, immutable type primarily intended to carry data in a _very_concise manner. Take this example from the JEP:

// The old way
class Point {
    private final int x;
    private final int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    int x() { return x; }
    int y() { return y; }

    public boolean equals(Object o) {
        if (!(o instanceof Point)) return false;
        Point other = (Point) o;
        return other.x == x && other.y = y;
    }

    public int hashCode() {
        return Objects.hash(x, y);
    }

    public String toString() {
        return String.format("Point[x=%d, y=%d]", x, y);
    }
}
// The new way
record Point(int x, int y) { }

A huge improvement. The eagle-eyed may notice that the record definition is missing some methods. That is because, for record classes, the compiler generates equals, hashCode, and toString for you. It also generates getters and setters as well. While the JEP officially states that this isn’t the opening salvo of a War on Boilerplate, it’s at least a nice test shot. :P

Conclusion

There is, of course, more in the release than what I’ve discussed here, and you may find other bits more interesting, but these are the things that I’m most excited about.

You can download it here and read the official release notes here. Congrats to the entire JDK team!

tags: Java

Quotes

Sample quote

Quote source