eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

1. Overview

Often we face a dilemma about whether to migrate to a newer version of Java or continue with the existing one. In other words, we need to balance the new features and enhancements against the total efforts that would be needed to migrate.

In this tutorial, we’ll walk through some extremely useful features available in the newer versions of Java. These features aren’t only easy to learn but can also be implemented quickly without much effort when planning to migrate from Java 8 to Java 17.

2. Using String

Let’s look at some of the interesting enhancements to the String class.

2.1. Compact String

Java 9 introduced Compact String, a performance enhancement to optimize the memory consumption of String objects.

In simple terms, a String object will be internally represented as byte[] instead of char[]. To explain, every char is made up of 2 bytes because Java internally uses UTF-16In most cases, String objects are English words that can be represented with a single byte which is nothing but LATIN-1 representation.

Java internally handles this representation based on the actual content of the String object: a byte[] for the LATIN-1 character set and a char[] if the content contains any special chars (UTF-16). So, it’s fully transparent to the developers using String objects.

Until Java 8, the String was internally represented as char[]:

char[] value;

From Java 9, it will be a byte[]:

byte[] value;

2.2. Text Block

Before Java 15, embedding multi-line code snippets will require explicit line terminators, String concatenations, and delimiters. To address this, Java 15 introduced text blocks that allow us to embed code snippets and text sequences more or less as-is. This is particularly useful when dealing with literal fragments such as HTML, JSON, and SQL.

A text block is an alternative form of String representation that can be used anywhere a normal double-quoted String literal can be used. For instance, a multi-line String literal can be represented without explicit usage of line terminators and String concatenations:

// Using a Text Block
String value = """
            Multi-line
            Text
            """;

Prior to this feature, a multi-line text was not so readable and it was complex to represent:

// Using a Literal String
String value = "Multi-line"
                + "\n" \\ line separator
                "Text"
                + "\n";
String str = "Multi-line\nText\n";

2.3. New String Methods

When dealing with String objects, we often tend to use third-party libraries such as Apache Commons for common String operations. Specifically, this is the case for utility functions to check blank/empty values and other String operations such as repeat, indentation, etc.

Subsequently, Java 11 and Java 12 introduced many such convenient functions so that we can rely on inbuilt functions for such regular String operations: isBlank(), repeat(), indent(), lines(), strip(), and transform().

Let’s see them in action:

assertThat("  ".isBlank());
assertThat("Twinkle ".repeat(2)).isEqualTo("Twinkle Twinkle ");
assertThat("Format Line".indent(4)).isEqualTo("    Format Line\n");
assertThat("Line 1 \n Line2".lines()).asList().size().isEqualTo(2);
assertThat(" Text with white spaces   ".strip()).isEqualTo("Text with white spaces");
assertThat("Car, Bus, Train".transform(s1 -> Arrays.asList(s1.split(","))).get(0)).isEqualTo("Car");

3. Records

Data Transfer Objects (DTO) are useful when passing data between objects. However, creating a DTO comes with a lot of boilerplate code such as fields, constructors, getters/setters, equals(), hashcode(), and toString() methods:

public class StudentDTO {
    
    private int rollNo;
    private String name;
    
    // constructors
    // getters & setters
    // equals(), hashcode() & toString() methods
}

Enter record classes, which are a special kind of class that can define immutable data objects in a much more compact way and identical to Project Lombok. Originally introduced as a preview feature in Java 14, the record class is a standard feature from Java 16:

public record Student(int rollNo, String name) {
}

As we can see, record classes require only the type and name of fields. Subsequently, the compiler generates the equals()hashCode(), and toString() methods in addition to the public constructor, private and final fields:

Student student = new Student(10, "Priya");
Student student2 = new Student(10, "Priya");
        
assertThat(student.rollNo()).isEqualTo(10);
assertThat(student.name()).isEqualTo("Priya");
assertThat(student.equals(student2));
assertThat(student.hashCode()).isEqualTo(student2.hashCode());

4. Helpful NullPointerExceptions

NullPointerExceptions (NPEs) are very common exceptions that every developer faces. In most cases, the error messages thrown by the compiler aren’t useful for identifying the exact object which is null. Also, recent trends towards functional programming and method chaining to write code expressively and compactly make it more difficult to debug NPEs.

Let’s see one such example with method chaining usage:

student.getAddress().getCity().toLowerCase();

Here, if the NPE is thrown in this line, pinpointing the exact location of the null object is difficult as three possible objects can be null.

Starting with Java 14, we can now instruct the compiler with an additional VM argument to get helpful NPE messages:

-XX:+ShowCodeDetailsInExceptionMessages

With this option enabled, the error message is much more precise:

Cannot invoke "String.toLowerCase()" because the return value of "com.baeldung.java8to17.Address.getCity()" is null

Note that, starting from Java 15, this flag is enabled by default.

5. Pattern Matching

Pattern matching addresses a common logic in a program, namely the conditional extraction of components from objects, to be expressed more concisely and safely.

Let’s look at the two features that support pattern matching in Java.

5.1. Enhanced instanceOf Operator

A common logic that every program has is to check a certain type or structure and cast it to the desired type to perform further processing.  This involves a lot of boilerplate code.

Let’s look at an example:

if (obj instanceof Address) {
    Address address = (Address) obj; 
    city = address.getCity();
}

Here, we can see there are three steps involved: a test (to confirm the type), a conversion (to cast to the specific type), and a new local variable (to further process it).

Since Java 16, Pattern Matching for instanceof operator is a standard feature to address this issue. Now, we can directly access the target type in a much more readable way:

if (obj instanceof Address address) {
    city = address.getCity();
}

5.2. Switch Expressions

Switch expressions (Java 14) are like regular expressions which evaluate or return a single value and can be used in statements. In addition, Java 17 enables us to use pattern matching (preview feature) to be used in Switch expressions:

double circumference = switch(shape) {
    case Rectangle r -> 2 * r.length() + 2 * r.width();
    case Circle c -> 2 * c.radius() * Math.PI;
    default -> throw new IllegalArgumentException("Unknown shape");
};

As we can notice, there’s a new kind of case label syntax. switch expressions use “case L ->” labels instead of “case L:” labels. Further, there’s no need for explicit break statements to prevent fall through. Moreover, the switch selector expression can be of any type.

When using the traditional “case L:” labels in Switch expressions, we must use the yield keyword (instead of break statement) to return the value.

6. Sealed Classes

The primary purpose of inheritance is the reusability of code. Yet, certain business domain models may require only the predefined set of classes to extend the base class or interface. This is specifically valuable when using Domain Driven Design.

To augment this behavior, Java 17 offers Sealed classes as a standard feature. In short, a sealed class or interface can only be extended or implemented by those classes and interfaces which are permitted to do so.

Let’s see how to define a sealed class:

public sealed class Shape permits Circle, Square, Triangle {
}

Here, the Shape class permits inheritance only to a restricted set of classes. In addition, the permitted subclasses must define one of these modifiers: finalsealed, or non-sealed:

public final class Circle extends Shape {
    public float radius;
}

public non-sealed class Square extends Shape {
   public double side;
}   

public sealed class Triangle extends Shape permits ColoredTriangle {
    public double height, base;
}

7. Conclusion

Over the years, Java has introduced a bunch of new features in a phased manner from Java 8 (LTS) to Java 17 (LTS). Each of these features aims to improve multiple aspects such as productivity, performance, readability, and extensibility.

In this article, we explored a selected set of features that are quick to learn and implement. Specifically, the improvements over the String class, record types, and pattern matching will make life easier for developers who migrate from Java 8 to Java 17.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Summer Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

Course – Summer Sale 2026 – NPI (All)
announcement - icon

Yes, we're now running our only Summer Sale. All Courses are 30% off until 20th July, 2026:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments