https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
Whenever you want a
null
value to be replaced with some default value instead, use MoreObjects.firstNonNull(T, T)
. As the method name suggests, if both of the inputs are null, it fails fast with a NullPointerException
. If you are using an Optional
, there are better alternatives -- e.g. first.or(second)
.
A couple of methods dealing with possibly-null
String
values are provided in Strings
. Specifically, we provide the aptly named:Google Guava isNullOrEmpty for collections
CollectionUtils.isEmpty() in commons-collections.
https://github.com/google/guava/wiki/PreconditionsExplained
https://stackoverflow.com/questions/34646554/java-util-objects-requirenonnull-vs-preconditions-checknotnull
there is one more subtle difference in general in favor of using
checkNotNull
which is reflected in the printf
style varargs form. For example using Guava Preconditions
you can do following:public void getInput(String companyName) {
String context = "Google";
String moreContext = "Facebook";
checkNotNull(companyName, "Why not try %s or %s", context, moreContext);
}
with
Objects.requireNonNull
you will have to do something likepublic void getInput(String companyName) {
String context = "Google";
String moreContext = "Facebook";
requireNonNull(companyName, "Why not try " + context + " or " + moreContext);
}
Reference: See bottom section of Preconditions Explained
Simple, varargs "printf-style" exception messages. (This advantage is also why we recommend continuing to use checkNotNull over Objects.requireNonNull introduced in JDK 7.)
EDIT: One thing to note though is that all args to the errorMessageTemplate are converted to String using
String.valueOf(arg)
so you can use only %s and not other type specifiers like %d or %f etc.https://medium.com/@hanru.yeh/collection-toarray-new-t-0-will-be-faster-than-collection-toarray-new-t-size-5b129fabfa88
Vectorized arraycopy in theObject[] toArray()
case is much faster than the type-checked arraycopy intoArray(new T[size])
andtoArray(new T[0])
. Alas, that does not help us if we want to getT[]
.toArray(new T[0])
seems faster, safer, and contractually cleaner, and therefore should be the default choice now.
https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
Item 54: Return empty collections or arrays, not nulls
Never return null instead of a zero-length array
Do not preallocate the array passed to toArray in hopes of improving performance. Studies have shown that it is counterproductive [Shipilëv16]:
// Don’t do this - preallocating the array harms performance! return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);
https://wiki.sei.cmu.edu/confluence/display/java/ERR08-J.+Do+not+catch+NullPointerException+or+any+of+its+ancestors
https://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
https://www.javaworld.com/article/2072719/effective-java-nullpointerexception-handling.html
https://crunchify.com/have-you-noticed-nullpointerexception-npe-there-are-few-best-practices-to-avoid-npe/
Try to use
containsKey()
, containsValue()
, contains()
checks.
Check if String is
null
of empty after trim()
operation
public static boolean isNullOrEmptyAfterTrim(String crunchifyStr) {
return (crunchifyStr == null || crunchifyStr.trim().length() == 0);
}
|
https://www.geeksforgeeks.org/null-pointer-exception-in-java/
- Invoking a method from a null object.
- Accessing or modifying a null object’s field.
- Taking the length of null, as if it were an array.
- Accessing or modifying the slots of null object, as if it were an array.
- Throwing null, as if it were a Throwable value.
- When you try to synchronize over a null object.
Comparing string variable with a string literal
Check all references obtained from 'untrusted' methods
File.listFiles()
can return null if /etc
is not a directory.
1. [Mandatory] Do not catch Runtime exceptions defined in JDK, such as
NullPointerException
and IndexOutOfBoundsException
. Instead, pre-check is recommended whenever possible.- Invoking methods on an object which is not initialized
- Parameters passed in a method are
null
- Calling
toString()
method on object which isnull
- Comparing object properties in
if
block without checkingnull
equality - Incorrect configuration for frameworks like spring which works on dependency injection
- Using
synchronized
on an object which isnull
- Chained statements i.e. multiple method calls in a single statement
3.4. Consider Primitives Rather than Objects
Null problem occurs where object references points to nothing. So it is always safe to use primitives as much as possible because they does not suffer with null references. All primitives must have some default values also attached so beware of it.
3.5. Carefully Consider Chained Method Calls
While chained statements are nice to look at in the code, they are not NPE friendly. A single statement spread over several lines will give you the line number of the first line in the stack trace regardless of where it occurs.
ref.method1().method2().method3().methods4();
These kind of chained statement will print only “NullPointerException occurred in line number xyz”. It really is hard to debug such code. Avoid such calls.
3.6. Use String.valueOf() Rather than toString()
3.8. Discourage Passing of Null Parameters
I have seen some method declarations where method expects two or more parameters. If one of parameter is passed as null, then also method works if some different manner. Avoid this.
In stead you should define two methods; one with single parameter and second with two parameters. Make parameters passing mandatory. This helps a lot when writing application logic inside methods because you are sure that method parameters will not be null; so you don’t put unnecessary assumptions and assertions.
4.1. instanceof operator
The instanceof operator is NPE safe. So, instanceof null always returns false. It does not cause a NullPointerException. You can eliminate messy conditional code if you remember this fact.
// Unnecessary code if (data != null && data instanceof InterestingData) { } // Less code. Better!! if (data instanceof InterestingData) { } |
https://javarevisited.blogspot.com/2013/05/ava-tips-and-best-practices-to-avoid-nullpointerexception-program-application.html
1) Call equals() and equalsIgnoreCase() method on known String literal rather unknown object
Always call equals() method on known String which is not null. Since equals() method is symmetric, calling a.equals(b) is same as calling b.equals(a), and that’s why many programmer don’t pay attention on object a and b. One side effect of this call can result in NullPointerException, if caller is null.
2) Prefer valueOf() over toString() where both return same result
Read more: https://javarevisited.blogspot.com/2013/05/ava-tips-and-best-practices-to-avoid-nullpointerexception-program-application.html#ixzz5sBY0CqJu
Read more: https://javarevisited.blogspot.com/2013/05/ava-tips-and-best-practices-to-avoid-nullpointerexception-program-application.html#ixzz5sBWtRMcl
https://dzone.com/articles/java-8-optional-avoid-null-and
https://stackify.com/optional-java/
https://winterbe.com/posts/2015/03/15/avoid-null-checks-in-java/
Outer outer = new Outer();
if (outer != null && outer.nested != null && outer.nested.inner != null) {
System.out.println(outer.nested.inner.foo);
}
We can get rid of all those null checks by utilizing the Java 8
Optional
type. The method map
accepts a lambda expression of type Function
and automatically wraps each function result into an Optional
. That enables us to pipe multiple map
operations in a row. Null checks are automatically handled under the hood.Optional.of(new Outer())
.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo)
.ifPresent(System.out::println);
An alternative way to achieve the same behavior is by utilizing a supplier function to resolve the nested path:
Outer obj = new Outer();
resolve(() -> obj.getNested().getInner().getFoo());
.ifPresent(System.out::println);
Calling
obj.getNested().getInner().getFoo())
might throw a NullPointerException
. In this case the exception will be caught and the method returns Optional.empty()
.public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
}
catch (NullPointerException e) {
return Optional.empty();
}
}
http://javahowto.blogspot.com/2006/07/not-your-typical-npe.html
You may have noticed it's the autoboxing, the implicit cast from Integer to int that has caused NPE. This line
1
| int version = project.getVersion(); |
1
| int version = project.getVersion().intValue(); |
Autoboxing does create objects which are not clearly visible in the code. So when autoboxing occurs performance suffers. If you see the Javadocs:
It is not appropriate to use autoboxing and unboxing for scientific computing, or other performance-sensitive numerical code. An Integer is not a substitute for an int; autoboxing and unboxing blur the distinction between primitive types and reference types, but they do not eliminate it.
Confused Equals
Autoboxing has brought with itself a lot of things that just are not obvious to a programmer. What would be the output of below code?
Here is what the above code prints:
If you are wondering what happened above, 2 was boxed to Integer and hence
equals
could not compare it with Long.
And 2L was boxed to Long and hence returned true.
Here is simple example that demonstrates the caching of int:
What would be the result of above code?
Ambiguous Method Calls
What would be the result of below code?
And the output is:
The answer is that the compiler will choose widening over boxing, so the output will be “I am primitive long.”
NullPointerException
While running the below code, NullPointerException(NPE) can be thrown and it is not quite obvious from the code if you are not aware of autoboxing. Eclipse will show the warning for this code, “Null pointer access: This expression of type Boolean is null but requires auto-unboxing.” Because I made it obvious to eclipse that testNPEvariable is null.
2. Mixing primitive and wrapper in relational or equality operator
If we use a wrapper object to compare against a primitive using relational operator (like “<" or ">“) the unboxing of that wrapper can cause
NullPointerException
.
Widening VS Boxing
Widening is transforming a variable to another with a wider type. For example
String -> Object
, byte -> int
, int -> long
etc. If overloading comes in a case where one method has “widened” parameter and other method has “boxed” parameter then the Widening takes priority than boxing, in other words Widening beats boxing. An example program is given below.
Before Java 1.5, you had to manually convert the wrapper class to its primitive form by calling a specific function. For example, if you created an ArrayList of Integers, you would need to call the
intValue()
function on the Integer object to get the primitive valueint x = arr.get(0); // Wrong, will give you an error
int x = arr.get(0).intValue(); // Correct!
With autoboxing/unboxing, Java will implicitly call these functions (such as
intValue
) from the wrapper classes when it notices you are trying to use the primitive value.
Normally,
map.get(x)
will return a Boolean object, but will also return null
if x
is not found in the HashMap. Note that null is a valid value for a Boolean object (or any Java object)
However, Java sees that I'm comparing a Boolean object with a boolean primitive, so it implicitly calls the Boolean object's
booleanValue()
function.
Because
map.get(x)
returns null, Java is actually implicitly calling booleanValue()
on the null object, hence the NullPointerException
!Solution
The solution is to check if the object is
null
before performing a comparisonif( map.get("a") != null && map.get("a") == true )
// do something
or, more simply,
if( map.get("a") != null && map.get("a") )
https://checkerframework.org/manual/#nullness-checker
The most important annotations supported by the Nullness Checker are @NonNull and @Nullable. @NonNull is rarely written, because it is the default. All of the annotations are explained in Section 3.2.
The Checker Framework’s nullness annotations are similar to annotations used in other tools. You might prefer to use the Checker Framework because it has a more powerful analysis that can warn you about more null pointer errors in your code. Most of the other tools are bug-finding tools rather than verification tools, since they give up precision, soundness, or both in favor of being fast and easy to use.
If your code is already annotated with a different nullness annotation, the Checker Framework can type-check your code. It treats annotations from other tools as if you had written the corresponding annotation from the Nullness Checker
NullPointerTester tester = new NullPointerTester(); tester.testAllPublicStaticMethods(Range.class); tester.testAllPublicStaticMethods(Range.class); tester.testAllPublicInstanceMethods(Range.all()); tester.testAllPublicInstanceMethods(Range.open(1, 3));
Use AbstractPackageSanityTests, ClassSanityTester or NullPointerTester
http://shzhangji.com/blog/2018/09/20/how-to-avoid-null-pointer-exception/
@NonNull
and @Nullable
with Checker Framework
Checker Framework works as a plugin to the
javac
compiler, to provide type checks, detect and prevent various errors. Follow the official document, integrate Checker Framework with maven-compiler-plugin
, and it will start to work when executing mvn compile
. The Nullness Checker supports all kinds of annotations, from JSR 305 to Eclipse built-ins, even lombok.NonNull
.
By default, Checker Framework applies
@NonNull
to all method arguments and return values. import org.springframework.lang.Nullable;
Checker Framework is especially useful for Spring Framework users, because from version 5.x, Spring provides built-in annotations for nullness check, and they are all over the framework code itself, mainly for Kotlin users, but we Java programmers can benefit from them, too. Take
StringUtils
class for instance, since the whole package is declared @NonNull
, those methods with nullable argument and return values are explicitly annotated with @Nullable
https://github.com/spring-projects/spring-framework/blob/master/spring-core/src/main/java/org/springframework/util/package-info.java
@NonNullApi
@NonNullFields
package org.springframework.util;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
Object checked = Objects.requireNonNull(arg, "arg must not be null");
We can also let Lombok generate the check for us, which will throw a more meaningful
NullPointerException
:- Use methods that already guard against
null
values, such asString#equals
,String#valueOf
, and third party libraries that help us check whether string or collection is empty.
1 2 3 4 5 6 7 8 9 10 11 12 13 | if (str != null && str.equals("text")) {} if ("text".equals(str)) {} if (obj != null) { obj.toString(); } String.valueOf(obj); // "null" // from spring-core StringUtils.isEmpty(str); CollectionUtils.isEmpty(col); // from guava Strings.isNullOrEmpty(str); // from commons-collections4 CollectionUtils.isEmpty(col); |
- For return values, if the type is
Collection
, return an empty collection instead of null; if it’s a single object, consider throwing an exception. This approach is also suggested by Effective Java. Good examples come from Spring’s JdbcTemplate:
1 2 3 4 5 6 7 8 9 10 | // return new ArrayList<>() when result set is empty jdbcTemplate.queryForList("SELECT 1"); // throws EmptyResultDataAccessException when record not found jdbcTemplate.queryForObject("SELECT 1", Integer.class); // works for generics public <T> List<T> testReturnCollection() { return Collections.emptyList(); } |
@NonNull
and @CheckForNull
with SpotBugs
SpotBugs is the successor of FindBugs. We can use
@NonNull
and @CheckForNull
on method arguments or return values, so as to apply nullness check. Notably, SpotBugs does not respect @Nullable
, which is only useful when overriding @ParametersAreNullableByDefault
. Use @CheckForNull
instead.
To integrate SpotBugs with Maven and Eclipse, one can refer to its official document. Make sure you add the
spotbugs-annotations
package in Maven dependencies, which includes the nullness check annotations.1 2 3 4 5 | <dependency> <groupId>com.github.spotbugs</groupId> <artifactId>spotbugs-annotations</artifactId> <version>3.1.7</version> </dependency> |
Chaining of methods is a common cause of NPE, but if you have a series of methods that return
Optional
, you can chain them with flatMap
, NPE-freely1 2 3 4 | String zipCode = getUser() .flatMap(User::getAddress) .flatMap(Address::getZipCode) .orElse(""); |
Java 8 Stream API also uses optionals to return nullable values. For instance:
1 2 3 4 | stringList.stream().findFirst().orElse("default"); stringList.stream() .max(Comparator.naturalOrder()) .ifPresent(System.out::println); |