Better Programming

Advice for programmers.

Follow publication

6 Java 17 Features I Didn’t Know About

Text blocks, Record classes, and more

Konrad
Better Programming
Published in
6 min readJan 8, 2022
Photo by Christopher Gower on Unsplash

I distinctly remember when Java 8 was released in 2014. That was an enormous step forward, a step towards making Java a functional programming language method references, functional interfaces, default methods, streams, null-safe optionals, what’s more, to want?

But Java was already so behind any other modern language that adding these features was just catching up rather than creating a breakthrough feature…

Nevertheless, I enjoyed new language features, as did my colleagues! And, to be honest, since then I haven’t been paying too much attention to new features in subsequent releases.

Not only were companies not willing to upgrade to JDK 9 or 10, but before the next LTS (long term support) release was made (September 2018) I was more focused on working with Scala and data processing.

But after almost 8 years I decided it is time to make sure I stay up-to-date with new language features! And going through all the updates several of them came to my attention as the ones which will change my way of programming similarly as Java 8 did.

I will not cover all the features, there are just too many of them. As the title says, I selected 6 which I found most interesting and which I did not know about! And one I am still waiting for, we will see how long…

This list is by no means created in any particular order, however, each feature mentions the JDK version it was released with!

Local Variable Type Inference aka var

As Java developers, we are used to explicitly specify all the types of variables we create.

Those of us who know how to use an IDE to simplify the process save tons of time but still the code we all produce is rather clunky and unreadable with all these unnecessary types.

A simple example would be:

List<String> names = List.of(“Bob”, “Jack”, “Meg”);

Do I really need the type declaration on the left? Like I did not expect a list of strings will create List<String>, right? It gets even more annoying when types become a bit more complex

List<String> names = List.of(“Bob”, “Jack”, “Meg”);Map<String, Long> namesFrequency = names.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

As lines get longer we might want to introduce a variable for groupingBy. By doing that we create a monster:

List<String> names = List.of(“Bob”, “Jack”, “Meg”);Collector<String, ?, Map<String, Long>> byOccurrence = Collectors.groupingBy(Function.identity(), Collectors.counting()Map<String, Long> namesFrequency = names.stream().collect(byOccurrence);

So now we are between a rock and a hard place. This simple example can be of course solved by breaking lines but things are not always so easy.

With the help of var and static imports we can greatly simplify example above:

var names = List.of(“Bob”, “Jack”, “Meg”);var byOccurrence = groupingBy(identity(), counting());var namesFrequency = names.stream().collect(byOccurrence);

I should probably finish here but I have to mention a very important consequence of switching types to var.

We “lose” types.

Do you know what is the type of names, byOccurrence or namesFrequency? One would guess these are the same as in the example with types, but no! Since types are inferred we String is lost in byOccurrence (how can compiler know identity() is String?), hence namesFrequency becomes Map<Object, Long>! This can be easily fixed by explicitly typing Function.identity():

var names = List.of(“Bob”, “Jack”, “Meg”);var byOccurrence = groupingBy(Function.<String>identity(), counting());var namesFrequency = names.stream().collect(byOccurrence);

But in order to get a permanent solution we need to have good support from our IDE!

Thankfully I use an IDE that shows inferred types and makes it easy for me.

Example how IntelliJ shows types!

Text Blocks

I don’t know if I can count how many times I almost lost my mind by breaking long strings in Java. Why would a modern language have support for multiline strings?

Finally, from 2020 Java 15 supports text blocks! I am so excited by the fact I no longer have to type dozens of “+” signs but I can simply do this:

String myMessage = “””“Hello, Java!”“””;

There is one catch though (and multiple other catches that I will elaborate on in a separate article). Text blocks are only blocks, you can’t use them in a single line like this:

String myMessage = “”” “Hello, Java!” “””;

This will cause a compilation error and any modern IDE should tell you this:

Illegal text block start: missing new line after opening quotes

This makes me sad and it means we still have to escape quotation marks:

String myMessage = “\”Hello, Java!\””;

The switch is now an expression.

To be honest there are too many improvements to switch expressions that have been made over years to explain them in this short paragraph. I will focus only on the most important one.

Have you ever got a tricky question on your Java interview: what will the following code block print?

The answer should always be “It’s the weekend, I refuse to work.” since no break; has been specified.

Java 14 takes the switch to the next level. It no longer is a simple statement but it is an expression now so it can return a value! And by making this improvement we no longer have to think about break; :-).

Have you noticed that switch produces a value that can be assigned to a variable? How cool is that?

Stay tuned for a more deep-dive article about switch expressions!

Pattern Matching

I am personally a fan of pattern matching. I love how flexible programming is when I can type a straightforward switch/match-case statement and get the value I expect. Scala does it the way I would expect every modern language does.

Java is still way behind Scala but recently there were several enhancements introduced, unfortunately, the “real” switch-case pattern matching is still in preview (as of Java 17).

The only pattern matching that exists nowadays since Java 16 has been released is instanceof pattern matching. What does instanceof pattern matching mean? Let’s look at a “typical” example pre-Java 16:

if (obj instanceof String ) {    String s = (String)obj;}

With this new feature it becomes:

if (obj instanceof String s) {
// your code here
}

Sealed classes

Sealed classes are in a sense very similar to final classes. The difference is very subtle — final classes cannot be extended at all (cannot have subclasses) and only classes can be final, an interface cannot be made final — it would not make sense.

sealed keyword accompanied by a permits keyword allows a class or an interface to be extended or implemented only by a set of specified classes or interfaces. As an example below:

sealed interface Animal permits Reptile, Bird, Mammal, Fish {}

A very important thing to keep in mind is that extending a sealed class or interface requires using sealed or non-sealed keywords! non-sealed simply unseals it and allows it to be subclassed :-).

sealed classes are a perfect replacement for enums but to use the full power of them we need to wait until pattern matching for switch becomes production-ready.

Record classes

I left the best one for the end. Even though it doesn’t seem like a huge enhancement it drastically increases developer productivity. For those with Scala background record class is very similar to the case class.

With record classes introduced in Java 16 we can avoid all the unnecessary boilerplate code and suddenly this:

Becomes this:

record Person (int age, int height) {}

Isn’t that cool?! And yes, curly braces have to be there — such a bummer :-(. To be precise — the record class is even better than the example I provided earlier. We no longer have to think about adding hashCode(), equals(), toString() — which usually are easily generated by a favorite IDE, but still, requires manual intervention every time you add a new field. For me, this was a long-awaited feature!

This was by no means an exhaustive list of features and enhancements, I listed only the ones which I liked the most and which I will start using ASAP.

For an in-depth description of records please check my other article Java Records in Depth

Did I miss any major enhancement? What is your favorite feature? Let me know.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (1)

Write a response