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.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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 – All Access – NPI EA (cat= Spring)
announcement - icon

All Access is finally out, with all of my Spring courses. Learn JUnit is out as well, and Learn Maven is coming fast. And, of course, quite a bit more affordable. Finally.

>> GET THE COURSE
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 – LambdaTest – NPI EA (cat=Testing)
announcement - icon

End-to-end testing is a very useful method to make sure that your application works as intended. This highlights issues in the overall functionality of the software, that the unit and integration test stages may miss.

Playwright is an easy-to-use, but powerful tool that automates end-to-end testing, and supports all modern browsers and platforms.

When coupled with LambdaTest (an AI-powered cloud-based test execution platform) it can be further scaled to run the Playwright scripts in parallel across 3000+ browser and device combinations:

>> Automated End-to-End Testing With Playwright

Course – Spring Sale 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – Spring Sale 2025 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

1. Overview

In this tutorial, we’ll see how to use HashMap in Java, and we’ll look at how it works internally.

A class very similar to HashMap is Hashtable. Please refer to a couple of our other articles to learn more about the java.util.Hashtable class itself and the differences between HashMap and Hashtable.

2. Basic Usage

Let’s first look at what it means that HashMap is a map. A map is a key-value mapping, which means that every key is mapped to exactly one value and that we can use the key to retrieve the corresponding value from a map.

One might ask why not simply add the value to a list. Why do we need a HashMap? The simple reason is performance. If we want to find a specific element in a list, the time complexity is O(n) and if the list is sorted, it will be O(log n) using, for example, a binary search.

The advantage of a HashMap is that the time complexity to insert and retrieve a value is O(1) on average. We’ll look at how that can be achieved later. Let’s first look at how to use HashMap.

2.1. Setup

Let’s create a simple class that we’ll use throughout the article:

public class Product {

    private String name;
    private String description;
    private List<String> tags;
    
    // standard getters/setters/constructors

    public Product addTagsOfOtherProduct(Product product) {
        this.tags.addAll(product.getTags());
        return this;
    }
}

2.2. Put

We can now create a HashMap with the key of type String and elements of type Product:

Map<String, Product> productsByName = new HashMap<>();

And add products to our HashMap:

Product eBike = new Product("E-Bike", "A bike with a battery");
Product roadBike = new Product("Road bike", "A bike for competition");
productsByName.put(eBike.getName(), eBike);
productsByName.put(roadBike.getName(), roadBike);

2.3. Get

We can retrieve a value from the map by its key:

Product nextPurchase = productsByName.get("E-Bike");
assertEquals("A bike with a battery", nextPurchase.getDescription());

If we try to find a value for a key that doesn’t exist in the map, we’ll get a null value:

Product nextPurchase = productsByName.get("Car");
assertNull(nextPurchase);

And if we insert a second value with the same key, we’ll only get the last inserted value for that key:

Product newEBike = new Product("E-Bike", "A bike with a better battery");
productsByName.put(newEBike.getName(), newEBike);
assertEquals("A bike with a better battery", productsByName.get("E-Bike").getDescription());

2.4. Null as the Key

HashMap also allows us to have null as a key:

Product defaultProduct = new Product("Chocolate", "At least buy chocolate");
productsByName.put(null, defaultProduct);

Product nextPurchase = productsByName.get(null);
assertEquals("At least buy chocolate", nextPurchase.getDescription());

2.5. Values with the Same Key

Furthermore, we can insert the same object twice with a different key:

productsByName.put(defaultProduct.getName(), defaultProduct);
assertSame(productsByName.get(null), productsByName.get("Chocolate"));

2.6. Remove a Value

We can remove a key-value mapping from the HashMap:

productsByName.remove("E-Bike");
assertNull(productsByName.get("E-Bike"));

2.7. Check If a Key or Value Exists in the Map

To check if a key is present in the map, we can use the containsKey() method:

productsByName.containsKey("E-Bike");

Or, to check if a value is present in the map, we can use the containsValue() method:

productsByName.containsValue(eBike);

Both method calls will return true in our example. Though they look very similar, there is an important difference in performance between these two method calls. The complexity to check if a key exists is O(1), while the complexity to check for an element is O(n), as it’s necessary to loop over all the elements in the map.

2.8. Iterating Over a HashMap

There are three basic ways to iterate over all key-value pairs in a HashMap.

We can iterate over the set of all keys:

for(String key : productsByName.keySet()) {
    Product product = productsByName.get(key);
}

Or we can iterate over the set of all entries:

for(Map.Entry<String, Product> entry : productsByName.entrySet()) {
    Product product =  entry.getValue();
    String key = entry.getKey();
    //do something with the key and value
}

Finally, we can iterate over all values:

List<Product> products = new ArrayList<>(productsByName.values());

3. The Key

We can use any class as the key in our HashMap. However, for the map to work properly, we need to provide an implementation for equals() and hashCode(). Let’s say we want to have a map with the product as the key and the price as the value:

HashMap<Product, Integer> priceByProduct = new HashMap<>();
priceByProduct.put(eBike, 900);

Let’s implement the equals() and hashCode() methods:

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }

    Product product = (Product) o;
    return Objects.equals(name, product.name) &&
      Objects.equals(description, product.description);
}

@Override
public int hashCode() {
    return Objects.hash(name, description);
}

Note that hashCode() and equals() need to be overridden only for classes that we want to use as map keys, not for classes that are only used as values in a map. We’ll see why this is necessary in section 5 of this article.

4. Additional Methods as of Java 8

Java 8 added several functional-style methods to HashMap. In this section, we’ll look at some of these methods.

For each method, we’ll look at two examples. The first example shows how to use the new method, and the second example shows how to achieve the same in earlier versions of Java.

As these methods are quite straightforward, we won’t look at more detailed examples.

4.1. forEach()

The forEach method is the functional-style way to iterate over all elements in the map:

productsByName.forEach( (key, product) -> {
    System.out.println("Key: " + key + " Product:" + product.getDescription());
    //do something with the key and value
});

Prior to Java 8:

for(Map.Entry<String, Product> entry : productsByName.entrySet()) {
    Product product =  entry.getValue();
    String key = entry.getKey();
    //do something with the key and value
}

Our article Guide to the Java 8 forEach covers the forEach loop in greater detail.

4.2. getOrDefault()

Using the getOrDefault() method, we can get a value from the map or return a default element in case there is no mapping for the given key:

Product chocolate = new Product("chocolate", "something sweet");
Product defaultProduct = productsByName.getOrDefault("horse carriage", chocolate); 
Product bike = productsByName.getOrDefault("E-Bike", chocolate);

Prior to Java 8:

Product bike2 = productsByName.containsKey("E-Bike") 
    ? productsByName.get("E-Bike") 
    : chocolate;
Product defaultProduct2 = productsByName.containsKey("horse carriage") 
    ? productsByName.get("horse carriage") 
    : chocolate;

4.3. putIfAbsent()

With this method, we can add a new mapping, but only if there is not yet a mapping for the given key:

productsByName.putIfAbsent("E-Bike", chocolate);

Prior to Java 8:

if(!productsByName.containsKey("E-Bike")) {
    productsByName.put("E-Bike", chocolate);
}

Our article Merging Two Maps with Java 8 takes a closer look at this method.

4.4. merge()

And with merge(), we can modify the value for a given key if a mapping exists, or add a new value otherwise:

Product eBike2 = new Product("E-Bike", "A bike with a battery");
eBike2.getTags().add("sport");
productsByName.merge("E-Bike", eBike2, Product::addTagsOfOtherProduct);

Prior to Java 8:

if(productsByName.containsKey("E-Bike")) {
    productsByName.get("E-Bike").addTagsOfOtherProduct(eBike2);
} else {
    productsByName.put("E-Bike", eBike2);
}

4.5. compute()

With the compute() method, we can compute the value for a given key:

productsByName.compute("E-Bike", (k,v) -> {
    if(v != null) {
        return v.addTagsOfOtherProduct(eBike2);
    } else {
        return eBike2;
    }
});

Prior to Java 8:

if(productsByName.containsKey("E-Bike")) {    
    productsByName.get("E-Bike").addTagsOfOtherProduct(eBike2); 
} else {
    productsByName.put("E-Bike", eBike2); 
}

It’s worth noting that the methods merge() and compute() are quite similar. The compute() method accepts two arguments: the key and a BiFunction for the remapping. And merge() accepts three parameters: the key, a default value to add to the map if the key doesn’t exist yet, and a BiFunction for the remapping.

5. How to Avoid Casting HashMap<String, Object> Value

The java.util.HashMap<K,V> class is a hash table based implementation of the Map interface. Let’s discuss how we can avoid casting an instance of type HashMap<String, Object>.

5.1. When We Need Casting

First, let’s introduce when we need casting. Consider the Product class example. When creating a collection of Products using a HashMap we’ve got the option of initializing the collection using HashMap<String, Object>:

HashMap<String,Object> objectMap  = new HashMap<String,Object>();

After initializing, we can add instances of the Product class. However, when we want to create an instance of HashMap<String, Product> to access the field values of a Product instance, we can’t mix instance types. To demonstrate, let’s try to assign the instance we created to a variable of type HashMap<String, Product>:

HashMap<String,Product> productMap =objectMap;

We get an error message error: incompatible types: HashMap<String,Object> cannot be converted to HashMap<String,Product>. Therefore, we must iterate over the HashMap<String, Object> collection and cast Object to Product for each value to create a type HashMap<String, Product> collection. Let’s use a JUnit 5 test to confirm that we can access the fields of the resulting collection directly:

@Test
public void whenUsingObjectAsHashMapGenericParameter_ShouldRequireCast() throws Exception {

    try { 
        HashMap<String,Object> objectMap  = new HashMap<String,Object>();  

        Product eBike = new Product("E-Bike", "A bike with a battery");
        Product roadBike = new Product("Road bike", "A bike for competition");

        objectMap.put("E-Bike", eBike);
        objectMap.put("Road bike", roadBike);

        HashMap<String,Product> productMap =new HashMap<String,Product>();

        for (Map.Entry<String, Object> entry : objectMap.entrySet()) {
            if(entry.getValue() instanceof Product){
                productMap.put(entry.getKey(), (Product) entry.getValue());
            }
        }

        Product product = productMap.get("E-Bike"); 
          
        String actualDescription = product.getDescription();
        String expectedDescription = new String("A bike with a battery");

        Assertions.assertTrue(actualDescription.equals(expectedDescription));   
 
    } catch (ClassCastException e){
        System.out.println(e.getMessage());
    }
}

The JUnit test passes when we correctly convert the Object type values to Product type values.

5.2. How to Avoid Casting

Although casting is an option, we can avoid it for a more concise code. We avoid casting by using appropriate generics parameters when initializing a HashMap. If the HashMap value is of type Product we parameterize using Product instead of the superclass Object:

HashMap<String,Product> objectMap  = new HashMap<String,Product>();

Let’s use JUnit 5 test to confirm that no casting is required, and the resulting object can be assigned to a variable of type HashMap<String,Product>:

@Test
public void whenUsingProperHashMapGenericParameters_ShouldNotRequireCast() throws Exception {
    HashMap<String,Product> productMap  = new HashMap<String,Product>(); 

    Product eBike = new Product("E-Bike", "A bike with a battery");
    Product roadBike = new Product("Road bike", "A bike for competition");

    productMap.put(eBike.getName(), eBike);
    productMap.put(roadBike.getName(), roadBike);

    Product product = productMap.get("E-Bike"); 

    String actualDescription = product.getDescription();
    String expectedDescription = new String("A bike with a battery");
    
    Assertions.assertTrue(actualDescription.equals(expectedDescription));

    HashMap<String,Product> objectMap = productMap;
    
    Assertions.assertSame(objectMap, productMap);
}

The two JUnit tests should pass, confirming that we can avoid casting.

6. HashMap Internals

In this section, we’ll look at how HashMap works internally and what are the benefits of using HashMap instead of a simple list, for example.

As we’ve seen, we can retrieve an element from a HashMap using its key. One approach would be to use a list, iterate over all elements, and return when we find an element for which the key matches. Both the time and space complexity of this approach would be O(n).

With HashMap, we can achieve an average time complexity of O(1) for the put and get operations and space complexity of O(n). Let’s see how that works.

6.1. The Hash Code and Equals

Instead of iterating over all its elements, HashMap attempts to calculate the position of a value based on its key.

The naive approach would be to have a list that can contain as many elements as there are keys possible. As an example, let’s say our key is a lower-case character. Then it’s sufficient to have a list of size 26, and if we want to access the element with key ‘c’, we’d know that it’s the one at position 3, and we can retrieve it directly.

However, this approach would not be very effective if we have a much bigger keyspace. For example, let’s say our key was an integer. In this case, the size of the list would have to be 2,147,483,647. In most cases, we would also have far fewer elements, so a big part of the allocated memory would remain unused.

HashMap stores elements in so-called buckets and the number of buckets is called capacity.

When we put a value in the map, the key’s hashCode() method is used to determine the bucket in which the value will be stored.

To retrieve the value, HashMap calculates the bucket in the same way – using hashCode(). Then it iterates through the objects found in that bucket and use key’s equals() method to find the exact match.

6.2. Keys’ Immutability

In most cases, we should use immutable keys. Or at least, we must be aware of the consequences of using mutable keys.

Let’s see what happens when our key changes after we used it to store a value in a map.

For this example, we’ll create the MutableKey:

public class MutableKey {
    private String name;

    // standard constructor, getter and setter

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        MutableKey that = (MutableKey) o;
        return Objects.equals(name, that.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

And here goes the test:

MutableKey key = new MutableKey("initial");

Map<MutableKey, String> items = new HashMap<>();
items.put(key, "success");

key.setName("changed");

assertNull(items.get(key));

As we can see, we’re no longer able to get the corresponding value once the key has changed, instead, null is returned. This is because HashMap is searching in the wrong bucket.

The above test case may be surprising if we don’t have a good understanding of how HashMap works internally.

6.3. Collisions

For this to work correctly, equal keys must have the same hash, however, different keys can have the same hash. If two different keys have the same hash, the two values belonging to them will be stored in the same bucket. Inside a bucket, values are stored in a list and retrieved by looping over all elements. The cost of this is O(n).

As of Java 8 (see JEP 180), the data structure in which the values inside one bucket are stored is changed from a list to a balanced tree if a bucket contains 8 or more values, and it’s changed back to a list if, at some point, only 6 values are left in the bucket. This improves the performance to be O(log n).

6.4. Capacity and Load Factor

To avoid having many buckets with multiple values, the capacity is doubled if 75% (the load factor) of the buckets become non-empty. The default value for the load factor is 75%, and the default initial capacity is 16. Both can be set in the constructor.

6.5. Summary of put and get Operations

Let’s summarize how the put and get operations work.

When we add an element to the map, HashMap calculates the bucket. If the bucket already contains a value, the value is added to the list (or tree) belonging to that bucket. If the load factor becomes bigger than the maximum load factor of the map, the capacity is doubled.

When we want to get a value from the map, HashMap calculates the bucket and gets the value with the same key from the list (or tree).

7. Conclusion

In this article, we saw how to use a HashMap and how it works internally. Along with ArrayList, HashMap is one of the most frequently used data structures in Java, so it’s very handy to have good knowledge of how to use it and how it works under the hood. Our article The Java HashMap Under the Hood covers the internals of HashMap in more detail.

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.

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

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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

Course – Spring Sale 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

Course – Spring Sale 2025 – NPI (All)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 25% off until 26th May, 2025:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)