Quantcast
Channel: Baeldung
Viewing all articles
Browse latest Browse all 4535

How to Implement Elvis Operator in Java 8

$
0
0
start here featured

1. Introduction

In Java 8, there is no built-in Elvis operator like in Groovy or Kotlin. However, we can implement our own Elvis operator using method references and the ternary operator. In this tutorial, we’ll explore how to implement the Elvis operator in Java 8.

2. Understanding the Elvis Operator

The Elvis operator is commonly used in languages like Groovy and Kotlin. It’s denoted by the ?: symbol and is used to provide a default value when the original value is null.

The operator evaluates the expression on its left-hand side and returns it if it isn’t null. If the expression on the left-hand side evaluates to null, it returns the expression on the right-hand side instead.

For example, in Kotlin, we can write val name = person.name?: “Unknown” to return the person’s name if it’s not null, or “Unknown” if it is.

3. Using the Ternary Operator

The ternary operator (?:) allows a concise ifelse construct within an expression. While not exactly the Elvis operator, it achieves similar null checks and default assignments.

Let’s consider a scenario where we have a method that retrieves a user’s name from a database. The method may return null if the user isn’t found. Traditionally, we’d perform a null check and assign a default value using the ternary operator:

User user = new User("Baeldung"); // Simulate user object return from database
String greeting = (user != null && user.getName() != null) ? user.getName() : "Hello, Stranger";
assertEquals("Baeldung", greeting);
User user = new User(null);
String greeting = (user != null && user.getName() != null) ? user.getName() : "Hello, Stranger";
assertEquals("Hello, Stranger", greeting);

The ternary operator provides a concise and expressive way to handle null checks and default assignments within expressions. However, it becomes cumbersome for nested null checks:

String address = user != null ? user.getAddress() != null ? user.getAddress().getCity() : null : null;

4. Using the Optional Class

The Optional class introduced in Java 8 is a powerful tool for handling null references safely. It represents the presence or absence of a value.

We can use methods like ofNullable() to create an Optional from a potentially null value and then chain map() operations to perform actions on the value if it exists. Finally, we use orElse() to specify a default value in case the Optional is empty:

Now, we want to transform the user’s name to uppercase if it exists, or return “Hello Stranger” otherwise:

User user = new User("Baeldung");
String greeting = Optional.ofNullable(user.getName())
  .map(String::toUpperCase) // Transform if present
  .orElse("Hello Stranger");
assertEquals("BAELDUNG", greeting);

In this code, Optional.ofNullable(user.getName()) creates an Optional from the user’s name, handling the possibility of null. We then use map(String::toUpperCase) to transform the name to uppercase if it exists. Finally, orElse(“Hello Stranger”) specifies the default greeting if the name is null:

User user = new User(null);
String greeting = Optional.ofNullable(user.getName())
  .map(String::toUpperCase)
  .orElse("Hello Stranger");
assertEquals("Hello Stranger", greeting);

This approach promotes null-safety and avoids potential NullPointerExceptions. 

5. Using a Custom Method

We can create a set of utility methods that take a target object and a function and apply the function to the target object if it isn’t null. We can even chain these methods together to create a chain of null-coalescing operations.

To create a custom utility method that mimics the Elvis operator, we define a method with generics to handle different types of values:

public static <T> T elvis(T value, T defaultValue) {
    return value != null ? value : defaultValue;
}

This method takes two parameters: the value to be checked for null and a default value to be returned if the value is null. The method then returns either value or defaultValue based on the null check:

User user = new User("Baeldung");
String greeting = elvis(user.getName(), "Hello Stranger");
assertEquals("Baeldung", greeting);
user = new User(null);
String greeting = elvis(user.getName(), "Hello Stranger");
assertEquals("Hello Stranger", greeting);

Using a custom utility method like elvis() offers several benefits over nested ternary operators. It improves code organization by encapsulating null-checking logic in a separate method, thereby enhancing code readability and maintainability.

Let’s take a look at this example:

User user = new User("Baeldung");
user.setAddress(new Address("Singapore"));
String cityName = elvis(elvis(user, new User("Stranger")).getAddress(), new Address("Default City")).getCity();
assertEquals("Singapore", cityName);

First, we check if user is null. If it’s null, it returns a new User object with the default value “Stranger“. Next, we retrieve address from the user object. If getAddress() returns null, we return a new Address object with the default city name “Default City“:

User user = new User("Baeldung");
user.setAddress(null);
String cityName = elvis(elvis(user, new User("Stranger")).getAddress(), new Address("Default City")).getCity();
assertEquals("Default City", cityName);

This chaining approach with the elvis() method allows us to handle nested null checks in a concise and readable manner, ensuring that our code gracefully handles null scenarios without resorting to verbose ifelse constructs.

6. Conclusion

In this article, we implemented the Elvis operator in Java 8 using the Optional class and ternary operator. Additionally, we created a custom utility method, elvis(), to handle null checks and default assignments. By encapsulating the logic within a method, we can improve code readability and maintainability while promoting code reusability.

As always, the source code for the examples is available over on GitHub.

       

Viewing all articles
Browse latest Browse all 4535

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>