How do I use !! and avoid NullPointerException in Kotlin?

In Kotlin, the !! operator is called the not-null assertion operator. It is used to tell the compiler that a null value will never be encountered for a given variable. If Kotlin encounters a null during runtime while using !!, it will throw a NullPointerException (NPE).

While using !! can be convenient in some cases, it is generally discouraged because:

  • It defeats Kotlin’s strong null-safety system.
  • It can lead to unexpected crashes if null values occur.

Example of !! usage:

val name: String? = getNullableName() // Can be null
val length = name!!.length // Throws NullPointerException if `name` is null.

If name happens to be null, the code will throw a KotlinNullPointerException.

Strategies to Avoid NullPointerException Without !!

Instead of using !!, you should take advantage of Kotlin’s powerful null-safety features:

1. Safe Call Operator (?.)

The ?. operator allows you to safely access properties or call methods on nullable objects. If the object is null, the operation is skipped, and null is returned.

val name: String? = getNullableName()
val length = name?.length // If `name` is null, `length` will also be null

2. Elvis Operator (?:)

The Elvis operator allows you to provide a default value if a nullable object is null.

val name: String? = getNullableName()
val length = name?.length ?: 0 // If `name` is null, default to `0`.

3. Null-Check with if Statements

You can perform explicit null checks using conditional statements.

val name: String? = getNullableName()
if (name != null) {
    val length = name.length
    println("Length: $length")
} else {
    println("Name is null")
}

4. let Extension Function

The let function is a great way to perform operations safely on a nullable value only if it is not null.

val name: String? = getNullableName()
name?.let {
    println("Length: ${it.length}")
} ?: println("Name is null")

5. Smart Casts

Kotlin’s type system can automatically cast a nullable value to a non-nullable type after a null check.

val name: String? = getNullableName()
if (name != null) {
    println("Length: ${name.length}") // Smart cast to non-nullable `String`.
}

6. Using Default Value in Functions

You can provide default values for parameters in functions to ensure they’re never null.

fun greet(name: String = "Guest") {
    println("Hello, $name!")
}

greet(null) // Compiler error
greet()     // Uses default value: "Hello, Guest!"

7. Require Non-Null Parameters

If a parameter cannot be null, declare it as a non-nullable type (String instead of String?). This way, Kotlin ensures null values are not passed to such parameters.

When to Use !!

Use !! only when you’re absolutely certain that the value is never null, and a null value would indicate a programmer error or an exceptional situation.
For example:

val bundle: Bundle = intent.extras!!
val value = bundle.getString("key")!!

In this case, you’re assuming that intent.extras and the value for the key "key" will always exist. However, it’s better to avoid such assumptions and handle null-safety appropriately.

Summary

  • Avoid !! as much as possible.
  • Use Kotlin’s built-in null-safety features like ?., ?:, if, let, and smart casts.
  • Reserve !! for situations where you’re certain about non-nullability (or avoid it altogether). Writing safer and more reliable code is one of Kotlin’s strong suits

How do I iterate through date range in Java?

The following code snippet shows you how to iterate through a range of dates in Java. We use the Java Date Time API. We do increment and decrement iteration using a simple for loop.

Here are the steps:

  • We declare the start and end date of the loop, the dates are instance of java.time.LocalDate.
  • Create a for loop.
  • In the for loop we set the initialization variable the start date.
  • The loop executed if the date is less than end date, using the isBefore() method, otherwise it will be terminated.
  • The date will be incremented by 1 on each loop.
package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.format.TextStyle;
import java.util.Locale;

public class DateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        System.out.println("Start = " + start);
        System.out.println("End   = " + end);
        System.out.println("--------------------");

        for (LocalDate date = start; date.isBefore(end); date = date.plusDays(1)) {
            System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek());
        }

        System.out.println("--------------------");

        for (LocalDate date = end; date.isAfter(start); date = date.minusDays(1)) {
            System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek()
                    .getDisplayName(TextStyle.SHORT, Locale.getDefault()));
        }
    }
}

Running the code snippet gives you the following output:

Start = 2023-10-01
End   = 2023-10-08
--------------------
Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY
--------------------
Date 10/08/23 is Sun
Date 10/07/23 is Sat
Date 10/06/23 is Fri
Date 10/05/23 is Thu
Date 10/04/23 is Wed
Date 10/03/23 is Tue
Date 10/02/23 is Mon

Next, we are going to use while loop.

  • Define the start and end date to loop
  • We increment the start date by 1 day.
  • Execute the loop if the start date is before end date.
package org.kodejava.datetime;

import java.time.LocalDate;

public class WhileDateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1).minusDays(1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        while ((start = start.plusDays(1)).isBefore(end)) {
            System.out.printf("Date %tD is %s%n", start, start.getDayOfWeek());
        }
    }
}

The result of the code snippet above is:

Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY

To use the Java stream, we can do it like the following code snippet:

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.stream.Stream;

public class StreamDateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        Stream.iterate(start, date -> date.plusDays(1))
                .limit(ChronoUnit.DAYS.between(start, end))
                .forEach(date -> {
                    System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek());
                });
    }
}

The result of the code snippet above is:

Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY

From Java 9 we can use LocalDate.datesUntil() method. It will iterate from the date to the specified end date by increment step of 1 day or the specified increment of Period.

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.Period;

public class DatesUntilDateIteration {
    public static void main(String[] args) {
        LocalDate start = LocalDate.of(2023, 10, 1);
        LocalDate end = LocalDate.of(2023, 10, 8);

        start.datesUntil(end).forEach(date -> {
            System.out.printf("Date %tD is %s%n", date, date.getDayOfWeek());
        });

        start.datesUntil(end, Period.ofDays(2)).forEach(System.out::println);
    }
}

Running the code snippet produces the following result:

Date 10/01/23 is SUNDAY
Date 10/02/23 is MONDAY
Date 10/03/23 is TUESDAY
Date 10/04/23 is WEDNESDAY
Date 10/05/23 is THURSDAY
Date 10/06/23 is FRIDAY
Date 10/07/23 is SATURDAY
2023-10-01
2023-10-03
2023-10-05
2023-10-07

How do I create a custom TemporalAdjuster?

In this example we are going to learn how to implement a custom TemporalAdjuster. We are going to create TemporalAdjuster to find the next working day from a specified date. We will use 5 working days, from Monday to Friday.

The custom temporal adjuster class should implement the TemporalAdjuster interface, which define a single method that we must implement, the adjustInto(Temporal) method.

package org.kodejava.datetime;

import java.time.DayOfWeek;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class NextWorkingDayAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        int field = temporal.get(ChronoField.DAY_OF_WEEK);
        DayOfWeek dayOfWeek = DayOfWeek.of(field);

        int daysToAdd = 1;
        if (DayOfWeek.FRIDAY.equals(dayOfWeek)) {
            daysToAdd = 3;
        } else if (DayOfWeek.SATURDAY.equals(dayOfWeek)) {
            daysToAdd = 2;
        }
        return temporal.plus(daysToAdd, ChronoUnit.DAYS);
    }
}

The NextWorkingDayAdjuster move the temporal object a day forward. Except if it is on Friday or Saturday, which will move the temporal object three days or two days forward respectively. This will make it return Monday as the next working day.

After creating the custom adjuster, now let’s create an example that use the NextWorkingDayAdjuster class.

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAdjuster;

public class NextWorkingDayAdjusterDemo {
    public static void main(String[] args) {
        TemporalAdjuster nextWorkingDay = new NextWorkingDayAdjuster();

        LocalDate now = LocalDate.now();
        LocalDate nextDay = now.with(nextWorkingDay);
        System.out.println("now            = " + now);
        System.out.println("nextWorkingDay = " + nextDay);

        LocalDate friday = LocalDate.of(2021, Month.MARCH, 11);
        nextDay = friday.with(nextWorkingDay);
        System.out.println("friday         = " + friday);
        System.out.println("nextWorkingDay = " + nextDay);

        LocalDate saturday = LocalDate.of(2021, Month.MARCH, 12);
        nextDay = saturday.with(nextWorkingDay);
        System.out.println("saturday       = " + saturday);
        System.out.println("nextWorkingDay = " + nextDay);
    }
}

And here are the results of our code:

now            = 2021-11-18
nextWorkingDay = 2021-11-19
friday         = 2021-03-11
nextWorkingDay = 2021-03-12
saturday       = 2021-03-12
nextWorkingDay = 2021-03-15

How do I manipulate LocalDate object using TemporalAdjuster?

In the previous example we manipulate the value of LocalDate by adding or subtracting the value of date object by days, months, years using methods like plusMonths() or minusDays(). Or by changing the year or the month of the date object using methods like withYear() or withMonth().

But there are times that we want to manipulate the date object so that we can get the first day of the month or the last day of the month. We want to manipulate the date value to advance the date to the first Monday after the current day or the last the of the year.

To manipulate the date object in this way we can use the with() method and pass a TemporalAdjuster object as an argument. Fortunately, the Date and Time API already provide some commonly used TemporalAdjuster. These TemporalAdjuster are provided as a static factory methods that we can find in the java.time.temporal.TemporalAdjusters class.

The following example is a code snippet to manipulate the date object using TemporalAdjuster / TemporalAdjusters class.

package org.kodejava.datetime;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

public class DateManipulationWithTemporalAdjuster {
    public static void main(String[] args) {
        LocalDate date = LocalDate.now();
        System.out.println("Current date       = " + date);

        LocalDate date1 = date.with(TemporalAdjusters.firstDayOfMonth());
        System.out.println("First day of month = " + date1);

        LocalDate date2 = date.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println("Last day of month  = " + date2);

        LocalDate date3 = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
        System.out.println("Next Monday        = " + date3);

        LocalDate date4 = date.with(TemporalAdjusters.lastDayOfYear());
        System.out.println("Last day of year   = " + date4);
    }
}

The result of the code snippet are:

Current date       = 2021-11-18
First day of month = 2021-11-01
Last day of month  = 2021-11-30
Next Monday        = 2021-11-22
Last day of year   = 2021-12-31

The table below shows the complete static factory methods provided by the TemporalAdjusters class.

Method Name Method Description
dayOfWeekInMonth Returns a new date in the same month with the ordinal day-of-week.
firstDayOfMonth Returns a new date set to the first day of the current month.
firstDayOfNextMonth Returns a new date set to the first day of the next month.
firstDayOfNextYear Returns a new date set to the first day of the next year.
firstDayOfYear Returns a new date set to the first day of the current year.
firstInMonth Returns a new date in the same month with the first matching day-of-week.
lastDayOfMonth Returns a new date set to the last day of the current month.
lastDayOfYear Returns a new date set to the last day of the current year.
lastInMonth Returns a new date in the same month with the last matching day-of-week.
next Returns the next day-of-week adjuster.
nextOrSame Returns the next-or-same day-of-week adjuster.
ofDateAdjuster Returns user-written adjuster.
previous Returns the previous day-of-week adjuster.
previousOrSame Returns the previous-or-same day-of-week adjuster.

How do I manipulate the value of LocalDate object?

In the following example we will learn how to manipulate a LocalDate object. There are many methods available for us to change the value of a LocalDate object. For example, we can change the year, month and day of LocalDate object. We can use methods like withYear(), withDayOfMonth(), plusYears(), minusMonths(), etc. All these methods will return a new LocalDate object, the original LocalDate will stay unchanged.

Let’s see the following code example for demonstration on how to manipulate the value of LocalDate object.

package org.kodejava.datetime;

import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;

public class LocalDateManipulation {
    public static void main(String[] args) {
        absoluteAttributeManipulations();
        relativeAttributeManipulations();
    }

    private static void absoluteAttributeManipulations() {
        System.out.println("LocalDateManipulation.absoluteAttributeManipulations");
        LocalDate date1 = LocalDate.of(2021, Month.JANUARY, 1);
        LocalDate date2 = date1.withYear(2010);
        LocalDate date3 = date2.withMonth(Month.DECEMBER.getValue());
        LocalDate date4 = date3.withDayOfMonth(15);
        LocalDate date5 = date4.with(ChronoField.DAY_OF_YEAR, 100);

        System.out.println("of(2021, Month.JANUARY, 1)                 => " + date1);
        System.out.println("date1.withYear(2010)                       => " + date2);
        System.out.println("date2.withMonth(Month.DECEMBER.getValue()) => " + date3);
        System.out.println("date3.withDayOfMonth(15)                   => " + date4);
        System.out.println("date4.with(ChronoField.DAY_OF_YEAR, 100)   => " + date5);
    }

    private static void relativeAttributeManipulations() {
        System.out.println("LocalDateManipulation.relativeAttributeManipulations");
        LocalDate date1 = LocalDate.of(2021, Month.AUGUST, 17);
        LocalDate date2 = date1.minusYears(70);
        LocalDate date3 = date2.plusMonths(10);
        LocalDate date4 = date3.minusDays(15);
        LocalDate date5 = date4.plusWeeks(52);
        LocalDate date6 = date5.minus(52, ChronoUnit.WEEKS);

        System.out.println("of(2021, Month.AUGUST, 17)        => " + date1);
        System.out.println("date1.minusYears(70)              => " + date2);
        System.out.println("date1.plusMonths(10)              => " + date3);
        System.out.println("date3.minusDays(15)               => " + date4);
        System.out.println("date4.plusWeeks(52)               => " + date5);
        System.out.println("date5.minus(52, ChronoUnit.WEEKS) => " + date6);

    }
}

The results of this code snippet are:

LocalDateManipulation.absoluteAttributeManipulations
of(2021, Month.JANUARY, 1)                 => 2021-01-01
date1.withYear(2010)                       => 2010-01-01
date2.withMonth(Month.DECEMBER.getValue()) => 2010-12-01
date3.withDayOfMonth(15)                   => 2010-12-15
date4.with(ChronoField.DAY_OF_YEAR, 100)   => 2010-04-10

LocalDateManipulation.relativeAttributeManipulations
of(2021, Month.AUGUST, 17)        => 2021-08-17
date1.minusYears(70)              => 1951-08-17
date1.plusMonths(10)              => 1952-06-17
date3.minusDays(15)               => 1952-06-02
date4.plusWeeks(52)               => 1953-06-01
date5.minus(52, ChronoUnit.WEEKS) => 1952-06-02