Introduction
The Objects class in Java has many useful static utility methods. In this post we will learn about the static utility methods in the Objects class in Java. I will also explain the methods added newly in Java 9 to the Objects class.
Objects#nonNull
The nonNull method takes an Object and returns true if the passed object is non-null and false otherwise. An example is:
System.out.println(Objects.nonNull("aa")); //true
System.out.println(Objects.nonNull(null)); //false
The real benefit/use of this method is to use it as a Predicate in the Java stream.
System.out.println(Stream.of("a", "b", null, "c")
.filter(Objects::nonNull)// s -> s != null
.collect(Collectors.toList())); //[a, b, c]
In the above example, we have a stream of strings and we are filtering out the nulls by calling Objects.nonNull.
Objects#isNull
The Objects.isNull method is the inverse of the nonNull method. It takes an object and returns true if the passed object is null and false otherwise.
System.out.println(Objects.isNull("aa")); //false
System.out.println(Objects.isNull(null)); //true
This too can be used as a Predicate function.
Objects#requireNonNull
The requireNonNull method is a generic method which checks if the passed reference is not null. It throws a NullPointerException if the passed reference is null and returns the same value back if it is non-null.
This is primarily used for doing parameter validation is methods and constructors. Let us say we have a class whose constructor accepts a string argument and assigns it to the instance variable. Before assigning, we can check if it is non-null using requireNonNull as:
public class MyClass {
private String name;
public MyClass(String name) {
this.name = requireNonNull(name);
}
public String getName() {
return name;
}
}
requireNonNull with exception message
The requireNonNull we saw will throw a NullPointerException with no message if the passed reference is null. There is another overloaded requireNonNull method which allows us to pass a message which will be used as the exception message (if it throws a NullPointerException).
Let us change the requireNonNull call as:
this.name = requireNonNull(name, "Name cannot be null");
If we pass a null value for name, it will throw java.lang.NullPointerException: Name cannot be null.
requireNonNull with a Supplier for exception message
This overloaded requireNonNull takes a Supplier<String> which is the exception message supplier. Use this if the construction of the exception message has a high performance impact. The supplier will be called only when it has to throw a NullPointerException.
this.name = requireNonNull(name, () -> "Name cannot be null");
Object - requireNonNullElse and requireNonNullElseGet
In Java 9, they added the requireNonNullElse and requireNonNullElseGet methods.
requireNonNullElse
The requireNonNullElse takes two arguments of the same type. It checks if the first argument is non-null and returns it if it is so. Or else, it returns the non-null second argument. Thus the second argument is the default value to use if the first argument is null. It will throw a NullPointerException if both the arguments are null.
Let us change the constructor of MyClass as:
this.name = requireNonNullElse(name, "DEFAULT_NAME");
System.out.println(new MyClass(null).getName()); //DEFAULT_NAME
Since we pass a null as the argument, the default value (the second argument) will be assigned to the name instance variable.
requireNonNullElseGet
The requireNonNullElseGet is like the requireNonNullElse method, but takes a Supplier<T> which will provide the default value when the first argument is null. Use this if the default value creation is costly as it will call the supplier only when the first argument is null.
this.name = Objects.requireNonNullElseGet(name, () -> "DEFAULT_NAME");
System.out.println(new MyClass(null).getName()); //DEFAULT_NAME
Objects - Methods to validate index
Now, let us look at the methods that we can use to validate indices. All these methods were added in Java 9. All these methods throw an IndexOutOfBoundsException if the index is out of the specified bounds.
checkIndex
The checkIndex method takes an index (int) and the length (int) and checks if the index is within the bounds of the range from 0 (inclusive) to length (exclusive). If the index is within the bounds, returns the index - else throws IndexOutOfBoundsException.
Objects.checkIndex(1, 5); //returns 1
//throws java.lang.IndexOutOfBoundsException: Index 6 out of bounds for length 5
Objects.checkIndex(6, 5);
In the first example, the index 1 is within the bound (1, 5]. In the second example, the index 6 is out of the bunds (1, 5] and hence it throws a IndexOutOfBoundsException.
checkFromToIndex
The checkFromToIndex method three arguments - fromIndex, toIndex and length. It checks it the sub-range from fromIndex (inclusive) and toIndex (exclusive) is within the bounds from 0 (inclusive) to length (exclusive) i.e., (0, length].
It returns the fromIndex if the range is within the bounds and throws an IndexOutOfBoundsException otherwise.
Objects.checkFromToIndex(0, 5, 5); //returns 0
//throws java.lang.IndexOutOfBoundsException: Range [0, 6) out of bounds for length 5
Objects.checkFromToIndex(0, 6, 5);
We are using the bounds as (0, 5]. In the first example the passed index range is (0, 5] and hence it is valid and it returns the lower bound (0). In the second example the upper bound (6) is out of the range and hence it throws an IndexOutOfBoundsException.
checkFromIndexSize
The checkFromIndexSize takes three arguments - the fromIndex, size and length. It checks if the sub-range from fromIndex (inclusive) to fromIndex + size (exclusive) is within the bounds of range 0 (inclusive) to length (exclusive). It will return the fromIndex if the sub-range is within the bounds of the range.
Objects.checkFromIndexSize(3, 2, 5); //3
//throws java.lang.IndexOutOfBoundsException: Range [3, 3 + 3) out of bounds for length 5
Objects.checkFromIndexSize(3, 3, 5);
In the above example, the range is (0, 5]. In the first example, the sub-range is (3, 5] i.e., 3 (inclusive) to 5 (exclusive) and hence the sub-range is valid.
For the second call, the sub-range is (3, 6] i.e., 3 (inclusive) to 6 (exclusive) and hence the sub-range is not valid.
Objects - hash and hashCode
The hashCode method returns the hash code of the passed argument (if non-null). If the argument is null, it will return a 0.
The hash method takes a var-args and generates a hash code for the passed values. The result is equivalent to placing all the elements in an array and calling Arrays#hashCode(Object[]).
This method is very useful to implement the hashCode for a custom class with multiple fields.
Let us implement the hashCode for a Student class:
public class Student {
private String name;
private int id;
private String grade;
public Student(String name, int id, String grade) {
this.name = name;
this.id = id;
this.grade = grade;
}
@Override
public int hashCode() {
return Objects.hash(id, name, grade);
}
@Override
public String toString() {
return "Student: " + name;
}
}
Objects - toString
The toString method takes an object and returns the result of calling the toString on that object. It returns the string “null” if the argument passed is null.
Objects.toString(new Student("John", 1, "A")); // Student: John
Objects.toString(null); // null
There is another overloaded toString method which takes a default value as the second argument. If the first argument is non-null, it returns the result of calling toString on it. It returns the default value if the first argument is null.
System.out.println(Objects.toString(null, "DEFAULT")); //DEFAULT
Objects#equals
The equals method takes two arguments and returns true if both are equal and false otherwise.
Note: If both arguments are null, it will return true and if one of them is null, it will return a false.
Objects.equals("a", "a"); //returns true
Objects.equals("a", "b")) //returns false
Objects#compare
The compare method is a generic method which takes two arguments and a comparator and returns the result of comparing both arguments using the comparator. It returns 0 if the arguments are identical; else returns the result of what the comparator returns.
System.out.println(Objects.compare("a", "a", Comparator.naturalOrder())); //0
System.out.println(Objects.compare("a", "c", Comparator.naturalOrder())); //-2
System.out.println(Objects.compare("c", "a", Comparator.naturalOrder())); //2
- In the first call, both are equal and hence by comparing strings by natural order, it returns a 0.
- In the second call, string “a” is less than “c” as per the natural order and hence we got a result which is less than 0.
- Finally, after switching the order, we got a result greater than 0.
Conclusion
In this post, we saw the static utility methods in the Objects class. Check out the other posts on classes and interfaces in Java.