Top Java trends of 2023: Project Loom, Spring, new features
Here's what's hot in the Java community right now, from new frameworks to language features you can leverage to get to production faster.
Sep 19, 2023 • 9 Minute Read
It seems like it was only 30 years ago that Java first grabbed everyone’s attention, and changed the face of software engineering for decades to come. But is it still relevant today?
In this article, we’ll take a look at this versatile and enduring programming language and how it continues to evolve and adapt to the ever-changing landscape of software development. From new language features to innovative frameworks and tools, let's explore what’s hot in the Java community right now.
Project CRaC
A lot has happened in the recent past to improve Java’s performance. These first three trends are all part of a larger effort to keep Java relevant on workloads where startup time, high-throughput concurrency, and tiny footprints are key.
The first of the three is Project CRaC, or Coordinated Restore at Checkpoint. You can think of this in the same way as hibernation on your laptop. If you close the lid on your laptop, most operating systems will take a snapshot of the current state of the computer. When you open it up, the operating system restores that snapshot. Doing so keeps the restoration process snappy and predictable. The same goes for Java workloads equipped with CRaC.
The initial findings from adding CRaC to your workloads are quite promising. The CRaC project itself reports that their sample Spring Boot restores improve Boot startup from 3,800 ms to 38 ms—an impressive 100x improvement. Likewise, Micronaut improves from 1,000 ms to 46 ms, and Quarkus improves from 980 ms to 33 ms.
At this point, CRaC is not part of Java SE, but you can try it out by following the CRaC team’s documentation in their GitHub repo.
Project Loom
Another active area of research for improving Java performance is Project Loom. It specifically aims to simplify and enhance concurrency in Java applications with two innovations: virtual threads (also called green threads) and structured concurrency.
While Java’s platform threads have performed well and gotten us quite far to date, they have their limitations. Platform threads are limited to the number of cores on a given machine. Context switching between platform threads is expensive. And platform threads can’t easily leverage CPU cache affinity. These limitations gave rise to strategies like thread pooling and request-per-thread, which have their own set of limitations (e.g., the potential for data to leak between thread usages).
To address this, Project Loom introduces virtual threads—lightweight threads managed by the JVM instead of the operating system. Since they’re managed by the JVM, their upper bound is orders of magnitude higher than the number of CPUs, the cost of switching is much lower, and it’s possible for the JVM to run similar tasks off the same stack. Research shows that similar applications that were limited to four platform threads (since there are four CPUs on the machine, say) can easily scale beyond 100,000 virtual threads.
Another common problem that arose in Java multi-threaded applications was the need for one thread to wait on and consume the result of another thread. Entire frameworks, like RxJava and Project Reactor, were born around this, as well as language-level constructs and APIs like the synchronized keyword and CompletableFuture.
As such, Project Loom also introduces structured concurrency: a simplified API that allows applications to describe a set of related concurrent operations as a complete task. This new API will make it simpler to cancel tasks through error propagation, see the task hierarchy, and (hopefully) remove the need for much of the complexity adopted over the years in the form of reactive programming.
Native compilation
The final of the three performance trends in Java is native compilation, which allows an application to be compiled into machine code instead of relying on a JVM to interpret intermediate bytecode.
Native compilation is made possible by GraalVM, a high-performance JDK that ships with a very handy native image utility. This utility uses ahead-of-time compiling, instead of a JVM’s traditional just-in-time compiling, to create native machine code. This ahead-of-time compiling also allows for a great deal of code trimming, reducing the overall size of an application. The result is an application that starts up almost instantly and maintains a very small footprint. It’s also naturally more safe, as the less code you ship, the less code you have to secure.
One challenge to adoption is the need to address the usage of the Java Reflections library. For GraalVM’s code pruning to work, it needs to determine ahead of time which classes are going to be used. Given that reflection obscures this choice until runtime, GraalVM can prune a class that it thinks isn’t needed but shows up as missing at runtime when accessed reflectively.
Because of this, frameworks like Spring that have long used reflection as its secret sauce have been hard at work to make sure GraalVM can correctly prune and optimize its framework code reliably.
Spring Framework, Quarkus, and Others
As already alluded to, enterprise Java frameworks are hard at work to keep up with Java’s innovations and changes in the industry as a whole.
Each finds itself competing to get the best startup time, memory footprint, and time to first byte. This is great for the Java ecosystem as a whole. When frameworks compete, we win. We should see these expanding their support for CRaC, Loom, and native compilation as time goes on.
In addition, being cloud ready, DevOps friendly, and open to community engagement continue to be high priorities for these high-powered Java frameworks.
Want to get started with the Spring Framework? Check out my article: “Getting started with Spring.”
Pattern matching, text blocks, and records
And last but not least, we have new language features. Though JDK 17 was officially released in September 2021, industry adoption is ongoing. Many of these features carry the twin goals of less boilerplate and less programmer error.
Look for these three features to make shifts big and small in the code you write.
Text blocks
Historically, multi-line Java strings have been quite unreadable, especially when it’s needed to escape quotes.
Consider the need to write some JSON code as a Java string, like this:
```java
String order = “{“ +
\”id\”: \”1de57f-3ac2\”, ” +
\”date\”: \”2023-08-11\”, ” +
\”total\”: \”314.15\”” +
“}”;
```
The additional quotes and escaping make it difficult to read and even more difficult to write.
If you’re in 2023 and still writing multi-line strings, it’s time to upgrade and try something like this instead:
```java
String order = “””
{
“id”: ”1de57f-3ac2”,
”date”: ”2023-08-11”,
”total”: ”314.15”
}
”””;
```
In addition to being more readable and easier to write, there’s the extra-nice benefit that what’s written now looks like native JSON.
Pattern matching
Pattern matching has been a bit of a theme across the last few Java releases. There are two specific instances that you should pay attention to (and then start hoping for more).
The first is instance of pattern matching. This feature is a welcomed evolution in Java and joins the process of type-checking and casting. Consider this scenario:
```java
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
double area = circle.calculateArea();
}
```
Now, with pattern matching, you can elegantly express this as:
```java
if (shape instanceof Circle circle) {
double area = circle.calculateArea();
}
```
Another nice thing to play with is when the if statement is negated, the variable scoping still applies in the else clause. Clever!
The second is pattern matching with switch, which takes on a similar look:
```java
Object data = "Hello, Java friends!";
switch (data) {
case String s -> System.out.println("String: " + s);
case Integer i -> System.out.println("Integer: " + i);
default -> System.out.println("Unknown data type");
}
```
Here, the type is matched and casted, like “instanceof,” but in the case clause.
Records
It’s not often these days that we get a new keyword in Java. And while it may seem that records are about boilerplate reduction, there is more than meets the eye.
Records are designed to encapsulate immutable data, sparing developers from the cumbersome getter, constructor, equals, and hashCode boilerplate. Their compact syntax effortlessly defines the blueprint for simple data containers, fostering a cleaner and more elegant codebase.
Consider a classic scenario, defining a Person class with a handful of properties:
```java
public class Person {
private final String name;
private final int age;
// Constructor, getters, equals, hashCode...
}
```
With records, this transforms into a succinct declaration:
```java
public record Person(String name, int age) {}
```
We get other benefits besides this succinctness. We don’t need to remember to mark the fields as final, naturally making records more thread safe. Since we don’t need to code hashCode and equals, we’re not prone to forgetting to implement one or the other. And the code that can go in record’s constructors is quite limited, making them more secure to serialize and deserialize.
Look for coming IDE support to help you translate your existing candidate classes into Java records and appreciate the resulting elegance, correctness, and security they afford.
Conclusion
The Java community is vital and engaged in solving relevant engineering problems at scale. Countless hours of research are being poured into making Java faster from the performance side and the crafting side. Embracing frameworks and new language features predictably get you to production faster (and allow you to sleep better at night).
Learning more about Java
If you’re keen to upgrade your Java skills, Pluralsight also offers a wide range of Java and Spring related courses that cater to your skill level. You can sign up for a 10-day free trial with no commitments. You can also perform an equally free roleIQ assessment to see where your Java skills currently stack up, with advice on where to shore up the gaps in your current skill set.
Below is a list of Pluralsight learning paths with courses for beginner, intermediate, and advanced Java courses — just pick the starting point that works for you. If you’re not sure where you’re at, each page has a skill assessment you can use that will recommend where you should start out.
And if you liked this article, here are some courses written by me that you can check out.