The Evolution of Java: Challenging Stereotypes and Embracing Modernity

On a flight from Zurich to Toronto, I found myself in an engaging conversation with a fellow passenger. Among various topics, our conversation navigated toward our careers and, inevitably, as I am a Java developer, towards the world of Java.

This gentleman, having worked with Java some 15-20 years ago, was surprised to learn that I still actively use the language. “Isn’t it slow?” he questioned. His question echoed a stereotype that I have often encountered, one that has stuck to Java from its earlier days.

However, this stereotype is not only outdated but also inaccurate. Java is no longer a slow language; in fact, it’s considered one of the most performant languages, and in some scenarios, it even outperforms C++. In this article, we will tackle and dismantle such stereotypes as we explore the exciting evolution of Java.

Java: From Its Inception to Now

When James Gosling and his team at Sun Microsystems released Java in 1995, it was touted as a revolutionary step in the world of programming languages. Java’s “write once, run anywhere” promise and its strong emphasis on security made it an immediate hit.

However, as the software landscape began to shift towards more dynamic and flexible languages, Java was somewhat left behind, earning a reputation as a verbose, old-fashioned language.

Today, thanks to ongoing and substantial upgrades to the language, Java is shedding these stereotypes. A slew of new features, alongside important improvements in existing ones, have kept Java not only relevant but also increasingly attractive for the modern developer.

Embracing Modernity: The New Features of Java

The modern versions of Java have brought in several compelling features that challenge the idea of Java as an old and rigid language.

Flexible Main Methods

 In a departure from the traditional ‘public static void main(String[] args)‘, Java now allows additional entry points to an application, providing more flexibility and expressiveness in how programs are written and executed.

This new addition allows the classic “Hello, World!” program to be simplified to:

class HelloWorld {
void main() {
System.out.println(“Hello, World!”);
}
}

We can further make the class declaration implicit. This further simplifies the “Hello, World!” program to:

void main() {
    System.out.println(“Hello, World!”);
}

If you are interested in reading more, read my news item published on infoQ: Breaking down Barriers: Introducing JDK 21’s Approach to Beginner-Friendly Java Programming

Records

With Records, Java provides a compact syntax for declaring classes which are supposed to be dumb data holders. This reduces the boilerplate code developers have to write, making the language learner more efficient. Consider the following class:

import java.util.Objects;

public final class User {
private final Long id;
private final String firstName;
private final String lastName;

public User(Long id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}

public Long id() {
return id;
}

public String firstName() {
return firstName;
}

public String lastName() {
return lastName;
}

@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (User) obj;
return Objects.equals(this.id, that.id) &&
Objects.equals(this.firstName, that.firstName) &&
Objects.equals(this.lastName, that.lastName);
}

@Override
public int hashCode() {
return Objects.hash(id, firstName, lastName);
}

@Override
public String toString() {
return “User[” +
“id=” + id + “, ” +
“firstName=” + firstName + “, ” +
“lastName=” + lastName + ‘]’;
}

}

This whole code can be written in one line with Record. 

public record User(Long id, String firstName, String lastName) {}

And that’s it.  

Sealed Classes 

Sealed classes (and interfaces) give developers more control over inheritance, providing a level of flexibility hitherto unseen in the Java world. 

If you’re interested in knowing more about the case of sealed classes, read this article: Java Sealed Classes: Building Robust and Secure Applications

Pattern Matching, Unnamed Patterns and Variables

The inclusion of these features ushers in a new level of expressiveness in the language, reducing the verbosity and making code easier to read and write.

For example, Unnamed pattern variables can be beneficial in switch statements where the same action is executed for multiple cases, and the variables are not used. Consider the following code: 

switch (b) {
    case Box(RedBall _), Box(BlueBall _) -> processBox(b);
    case Box(GreenBall _) -> stopProcessing();
    case Box(_) -> pickAnotherBox();
}

If you’re interested in knowing more about it, read this article: JEP 443: Unnamed Patterns and Variables Aims to Improve Java Code Readability

String Templates

Java developers can now enhance the language’s string literals and text blocks with string templates that can produce specialized results by coupling literal text with embedded expressions and processors.

The aim of this new feature is to simplify the writing of Java programs, improve the readability of expressions that mix text and expressions, and enhance the security of Java programs that compose strings from user-provided values. Consider the following example: 

String name    = “Joan Smith”;
String phone   = “555-123-4567”;
String address = “1 Maple Drive, Anytown”;

String json = STR.”””
    {
        “name”:    “{name}”,
        “phone”:   “{phone}”,
        “address”: “{address}”
    }
    “””;

This produces the following output.

| “””
| {
|     “name”:    “Joan Smith”,
|     “phone”:   “555-123-4567”,
|     “address”: “1 Maple Drive, Anytown”
| }
| “””

Read the following infoQ item to know more about it: Java Gets a Boost with String Templates: Simplifying Code and Improving Security

Java’s Handling of Concurrency

Java’s improved handling of concurrency is another example of its modernization. The introduction of Virtual Threads (previously known as Project Loom) simplifies concurrent programming by making it easier to write, debug, profile, and maintain concurrent applications.

Additionally, Java’s Structured Concurrency prevents common programming errors, making concurrent programming safer and more efficient.

To know more about read the following article I have written:

A Comprehensive Guide to Java Virtual Threads (Part 1) | Foojay.io

JEP 444: Virtual Threads Arrive in JDK 21, Ushering a New Era of Concurrency

Structured Concurrency in JDK 21: A Leap Forward in Concurrent Programming

The Journey Ahead

While Java’s transformation has been significant, it is far from over. With its robust ecosystem and the Java Community Process continually pushing for enhancements, the future is bright.

The Java we know today is not just a language capable of meeting the demands of modern software development but also one that is continually evolving to anticipate future needs.

In conclusion, Java is no longer your dad’s language. It’s a modern, expressive, and efficient tool that is more than capable of taking on the challenges of the contemporary development world.

The stereotypes have been challenged, and Java stands tall, embracing modernity.

The post The Evolution of Java: Challenging Stereotypes and Embracing Modernity appeared first on foojay.