How to check if two ZonedDateTime objects represent the same day?

ZonedDateTime has been introduced in Java 8 and is a great choice when you would like to work with dates that contain time zone information.

It has an awesome truncatedTo(...) method, that lets you truncate it to specific parts. If we would like to check if two ZonedDateTime objects refer to the same day, we could use this method to first truncate them to days, then we can compare them using the equals method.

Here is an example of a method that does this:

private boolean isSameDay(ZonedDateTime date1, ZonedDateTime date2) {
    return date1.truncatedTo(ChronoUnit.DAYS).equals(date2.truncatedTo(ChronoUnit.DAYS));

Of course, if you want to do the check for something else (like hours, months, etc.), you can use a different ChronoUnit.

What is String interning in Java?

What does interning mean?

In a Java application, you can create a lot of String instances with the same content. Without String interning all of these would occupy separate memory areas as separate objects. If there are lots of them, this could mean a significant amount of memory.

String interning in Java is basically the way of storing only one copy of each distinct String value. As you will see, in a lot of cases it happens automatically, but in some cases, you have to do it manually by calling the String.intern() method.

How does it work?

Because Strings can be the same often, a so called String Pool is implemented in Java. The String Pool lives in the Heap memory and it stores each of the interned Strings in your application. The String Pool is privately maintained in the String object.

When you create a new String and intern it, Java checks if this String is already present in the String Pool. If it is there, a reference to that String object is returned and no new object is created. If it is not there, a new String object is created and stored in the String Pool and a reference to the new object is returned.

When should I use interning?

Automatic interning

As I mentioned, there are cases when interning happens automatically. Let me quote from the JavaDoc of the intern() method:

“All literal strings and string-valued constant expressions are interned.”

So the following two Strings will be interned automatically (first is a literal, second is a string-valued constant expression):

String a = "John";
String b = "Jane" + "Doe";

Manual interning

Other than the above-mentioned cases, interning does not happen automatically. Let’s take an example when you create two String variables and concatenate them into new variables:

String a = "John";
String a2 = "John";
String b = "Doe";
String c1 = a + b;
String c2 = a + b;

In this case, the “John” and “Doe” Strings are interned (stored in the String Pool), so only one object containing “John” and one with “Doe” is created.

However, the “JohnDoe” String is not interned and as a result, not stored in the String Pool. Because of this, the above code will create two String objects that contain the “JohnDoe” String.

To use interning manually, you can call the intern method on the resulting String like this:

String c1 = (a + b).intern();
String c2 = (a + b).intern();

This ensures that only one String object will be created with the content of “JohnDoe” and it will be stored in the String Pool.

Memory savings by interning

As I described above, interning allows you to reuse the same String objects multiple times. Of course, this results in less memory usage in the Heap space, where objects are stored.

The savings depend on your application. In small apps, you might not notice the difference, but in case of a lot of Strings the memory gain can be significant.


I have put together a small test application to demonstrate that:

package com.jtuts;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) throws InterruptedException {

        List<List<String>> listOfLists = new ArrayList<>();

        IntStream.range(0, 10).forEach(i -> {
            try {

                System.out.println("Starting iteration " + i);

                List<String> list = IntStream.range(0, 100000).mapToObj(j -> {
                    String s2 = "123123123123123123123123123123123123123";
                    return s1 + s2;


            } catch (InterruptedException e) {}


This application will attempt to create 10 x 100 000 quite long String objects. As you can see, I am creating two Strings via literals (these will be interned automatically), but then I concatenate them, creating a brand new String that will not be automatically interned.

I am collecting all these Strings in a List, so the Garbage Collector won’t remove any of them from the String Pool until the end of my application. I also added some delays so the memory allocation changes are more visible.

I started the application and also started up JConsole, and this is what I saw:

As you can see, my application is using more than 200 MB of Heap memory. That’s a lot. It is because we have created 1 million pretty big Strings and did not intern them.

Now let’s see what happens if I change the row where I return s1 + s2 to the following:

(s1 + s2).intern()

If I run the application again, now I get the following chart:

As you can see, the Heap memory usage doesn’t even reach 30 MB, which is way less than the first version.

The takeaway from this example is that if you have a large enough application that is for some reason producing a lot of Strings with the same content, then using interning can save you a lot of memory.

The effect of interning on comparison performance

As you probably know, when you want to compare two Strings by content you have to use the equals() method of the String object. This goes through the Strings and compares them character by character. In case of a lot of comparisons, this could take a considerable amount of time.

But wait! There is another way of comparing two objects. By using the double equals operator (==). However, the problem is, that we cannot use this for String content comparison as they only compare the reference of the objects, which might not be the same, even for Strings with the same content.

This example shows it to you very well:

String s1 = "John";
String s2 = "Doe";
String s3 = "JohnDoe";
String s4 = s1 + s2;

System.out.println(s3 == s4);

But what if we intern the Strings first and then do the double equals comparison? Exactly! That will work, because as I mentioned earlier, by interning you make sure that two Strings with the same content will refer to the same object in the String Pool.

String s1 = "John";
String s2 = "Doe";
String s3 = "JohnDoe";
String s4 = (s1 + s2).intern();

System.out.println(s3 == s4);

As you can see, this works and comparing two references if much faster than comparing two Strings character by character.

So, should I use interning all the time?

No, definitely not.

First of all, not all applications would benefit considerably from interning. For a noticeable benefit, the application has to handle a lot of large String objects that have the same content. I think that is rarely the case.

Secondly, using interning means a lot of overhead. You have to add the intern() method call to a lot of places and if you plan to use the double equals on your Strings for performance reasons, you have to be absolutely sure that intern() is used everywhere, where it is necessary. Because if you miss some occurrences, your comparisons could give you wrong results.

All in all, I think that by default interning should be skipped completely. However, if you suspect that your application could benefit considerably from using it, it is worth to check out the possible benefits.

How to create a list of objects using a range of numbers in Java 8

The Java 8 Stream API could come in handy when you would like to generate a series of objects for example for using them in a unit test.

The following snippet generates a list of 5 User objects with the id and name populated:

List<User> users = IntStream.range(0, 5).mapToObj(i -> {

    User user = new User();
    user.setName(USER_NAME_PREFIX + String.valueOf(i));

    return user;


If you have a suitable constructor, you can even make it a lot shorter:

List<User> users = IntStream.range(0, 5)
    .mapToObj(i -> new User(i, USER_NAME_PREFIX + String.valueOf(i)))


How to remove unnecessary trailing zeros from the string representation of a number

Recently I have had an issue where I needed to display some numbers that was sent to an application as strings. A lot of these numbers had some unnecessary trailing zeros at the end. I needed to remove these zeros, but keep the precision of the numbers.

The BigDecimal class came to my help. I converted my strings to BigDecimal instances and I was able to remove the unnecessary zeros and get back a string again the following way:

new BigDecimal("123.45600").stripTrailingZeros().toPlainString()

The result of this is another string, but without the trailing zeros.


This works with any other number, it won’t loose precision, just removes unnecessary zeros.

Keep form field values and errors after redirection in Spring MVC controller

Ways for processing form submit

When you are processing a form submit using Spring MVC, if there are validation errors, you can:

  1. Return the errors in the response to the form submit request (POST request usually).
  2. Redirect the user to the form and return the result from this new request.

The first option has a drawback that if the user refreshes the page after we return with the response, the form will be resubmitted the same way as before (also he’ll see the confirmation popup asking if it is okay to do that). On one hand, most of the users won’t even understand the situation, on the other hand if the user decides to resubmit the form, sometimes unwanted situations might happen.

Also, another case to consider, if the user just wants to refresh the page to get an empty form, he’ll not succeed because he’ll still see the errors and filled values from the previous submission.

Because of these reasons the second option might be preferred, let’s see how to do that

Retaining filled values and errors upon redirect

First let’s see the whole code of a controller that implements the solution:

package com.devsphinx.web.controller.user;

import com.devsphinx.web.controller.BaseController;
import com.devsphinx.web.model.user.CreateAccountModel;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.validation.Valid;

public class CreateAccountController extends BaseController {

    @RequestMapping(value = "/create-account", method = RequestMethod.GET)
    public String getCreateAccount(Model model) {

        if (!model.containsAttribute("createAccountModel")) {
            model.addAttribute("createAccountModel", new CreateAccountModel());

        return "create-account/create-account";

    @RequestMapping(value = "/create-account", method = RequestMethod.POST)
    public String postCreateAccount(
            @Valid CreateAccountModel createAccountModel,
            BindingResult result, RedirectAttributes redirectAttributes) {

        if (result.hasErrors()) {
            redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.createAccountModel", result);
            redirectAttributes.addFlashAttribute("createAccountModel", createAccountModel);
            return "redirect:/create-account";
        // Success case omitted...

You can see that we have here a standard spring controller with two methods. The first method serves the GET request for the account creation page and the second one serves the POST request.

What we wanted to achieve is if the POST request is performed and there are validation errors, then the request is redirected to the GET handler with the errors and form field values still populated.

In the POST handler method

if (result.hasErrors()) {
    redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.createAccountModel", result);
    redirectAttributes.addFlashAttribute("createAccountModel", createAccountModel);
    return "redirect:/create-account";

In this, we have to populate these to the RedirectAttributes instance.

  • For the BindingResult you have to specify the class with the full package name and contatenate the model’s name to the end.
  • The model must be added with the same name as you were using in this method.

In the GET handler method

@RequestMapping(value = "/create-account", method = RequestMethod.GET)
public String getCreateAccount(Model model) {

  if (!model.containsAttribute("createAccountModel")) {
    model.addAttribute("createAccountModel", new CreateAccountModel());

  return "create-account/create-account";

If we redirect from the POST handler, because we added the flash attributes, the model in the GET handler will be automatically populated with these.

However, if we reach the GET handler with just a regular page request, without anything added as flash attributes, we need to manually add the our form backing object (createAccountModel) to the model.