In this article, I’ll try to give some examples of different types of null checking or NPE (NullPointerException) avoidance techniques.

There are many good articles written on this topic, but I will try to highlight some specific examples from my own experience.

Please note that I’m still in the process of learning — which could be never-ending :)– so if you see any mistakes, please feel free to let me know about it.

1. java.util.Optional

A container object that may or may not contain a non-null value. If there is a value, isPresent(), it will return true, and get() will return the value ¹.

In the project I’m currently working on, one of the most common uses of Optional is when retrieving data from a database.

Let’s say you have three things.

  1. A model class calledStudent.java
  2. A service interface and its implementation:StudentService.javaStudentServiceImpl.java
  3. A DAO interface and its implementation:StudentDao.javaStudentDaoImpl.java

And you want to retrieve the student with the relevant ID.

Optional.ofNullable()

Returns an Optional that describes the given value if it is not empty, or an empty Optional otherwise.

The return value of this method is never empty. If it is empty, the return value will be optional.empty (). This way, if the results of this method are used elsewhere, there is no chance of getting an NPE.

Optional.orElseThrow()

If a value exists, it is returned, otherwise nosuchelementException.¹ is thrown.

In the case of null, if you want to throw an exception, you can just use orElseThrow().

Optional. OrElse ()

If a value exists, that value is returned, otherwise something else is returned.

In the null case, if you don’t want to throw an exception, but you want to return a sample student instance, you can use orElse().

@Overridepublic Student getMockStudent(Long id) { final var student = Student.builder() .id(1L) .name("ege") .build(); return studentDao.findStudentsById(id).orElse(student); }Copy the code

Optional.get()

If a value exists, it is returned, otherwise nosuchelementException.¹ is thrown.

@Overridepublic Student getStudentDirectly(Long id) { return studentDao.findStudentsById(id).get(); }Copy the code

In this case, if you use IntelliJ, it will immediately give you a warning.

Basically it’s saying “first check if your student is empty and then proceed”.

// correct way to do it@Overridepublic Student getStudentDirectly(Long id) {    final var studentOptional = studentDao.findStudentsById(id);    if(studentOptional.isPresent()){        // do your stuff here     }}
Copy the code

In unit tests, I mostly use get() when I’m sure there’s data coming back from a method I called. But in real code, IF there is no isPresent(), I won’t use it, even though I’m sure there won’t be null.

Another example; The code below attempts to get a student with a relevant ID, or if there is none, returns a default name (“Hayley”). The value passed to rElse() is also returned when there is a student but no name.

@Overridepublic String getStudentName(Long id) { return studentDao.findStudentsById(id) .map(Student::getName) .orElse("Hayley"); }Copy the code

2.apache.commons utility class

  • For the collection instance:CollectionUtils.isEmpty()CollectionUtils.isEmpty()
  • For the map example:MapUtils.isEmpty()MapUtils.isNotEmpty()
  • For strings:StringUtils.isEmpty()orStringUtils.isNotEmpty()

For lists, maps, etc., isEmpty() checks if the collection/map isEmpty or size 0. Similarly, for strings, check whether the String is empty or has a length of 0.

To use CollectionUtils and MapUtils, you need to add the following dependencies to the build.gradle file.

Implementation org.apache.com mons: Commons - collections4:4.4Copy the code

With StringUtils, you’ll need.

Implementation org.apache.com mons: Commons - lang3:3.0Copy the code

3. Objects::nonNull in the stream

Return true if the supplied reference is non-empty, false.² otherwise.

Suppose you have a data stream and you are going to do some chaining on the data stream, but before you do that you want to filter out null values (if any).

final var list = Arrays.asList(1, 2, null, 3, null, 4); list.stream() .filter(Objects::nonNull) .forEach(System.out::print);Copy the code

The result is. 1234

4. RequireNonNull method for java.util.Objects

requireNonNull()

Checks if the specified object reference is null and throws a custom *NullPointerException* if so. This method is designed primarily for parameter validation in methods and constructors that have multiple parameters.

requireNonNullElse()

If the first argument is non-null, the first argument is returned, otherwise the second non-null argument is returned. after

requireNonNullElseGet()

If the first argument is non-null, it is returned, otherwise the non-null value eastern.get () is returned. after

The places I use these three parameters most often are mainly constructors.

Let’s look at them through the example above.

RequireNonNull on ID: We are saying “this field is required, so if it is empty, throw an NPE message with” ID is required “.

RequireNonNullElse on Name: We’re saying “This field is required, so if it’s empty, don’t throw an exception, but set a default value for it.” In our example, the default value is “Hayley”.

RequireNonNullElseGet on classes: We’re saying “This field is required, so if it’s empty; Instead of throwing an exception, set a default value for it. .

Unlike requireNonNullElse, this method wants Supplier as the second parameter.

Therefore, we can use the method reference requireNonNullElseGet. It is especially useful when dealing with Lists, Maps, Sets, if you want to initialize them to empty Lists, Maps, Sets, etc.

RequireNonNullElseGet has no component-1

RequireNonNullElseGet without Supplier – 2

RequireNonNullElseGet was replaced with requireNonNullElse

Let’s look at action.

The results.

Student 1 name: hayleyStudent 2: Student(id=1, name=ege, classes=[], teacherMap={})Student 3: Student(id=null, name=null, classes=null, teacherMap=null)Student 4: Student(id=1, name=ege, classes=[], teacherMap={})Student 5: Student(id=1, name=ege, classes=[SchoolClass(id=null, name=null, type=null, teacher=null, students=null, extras=null, startDate=null)], teacherMap={})
Copy the code

Note that these validations are valid only if the associated constructor is called.

Another example; Suppose you are calling a method (y) from your current method (x), and with the result returned by (y), you will do something else in x. If you don’t check to see if the result returned from y is null, you might get NPE.

Results.

Students 1: nullStudents 2: []Students 3: [Student(id=1, name=ege, classes=[], teacherMap={}), Student(id=2, name=itir, classes=[], teacherMap={})]Students 4: [Student(id=1, name=itir, classes=[], teacherMap={}), Student(id=2, name=ege, classes=[], teacherMap={})]Default student name: hayleyAll names:[itir, ege]
Copy the code

5. The Builder Lombok. Default

If you’re not familiar with Lombok, I strongly encourage you to check it out. I personally love Lombok and it makes life easier for developers 🙂

Suppose you have Student.java with fields like ID, name, and class. You can use @Builder.Default to precede the related field and give it a Default value.

When an instance of the Student class is created, its “classes “will be an empty list, not empty.

final var student1 = Student.builder().build(); final var student2 = new Student(); final var student3 = Student.builder().id(1L).name("ege").build(); System.out.println(student1.getClasses()); System.out.println(student2.getClasses()); System.out.println(student3.getClasses()); System.out.println(student1.getName()); System.out.println(student2.getName()); System.out.println(student3.getName());Copy the code

The result is.

[][][]hayleyhayleyege
Copy the code

If you simply state fields in Student.java like this.

private Long id; private String name; private List<SchoolClass> classes;Copy the code

Results.

nullnullnullnullnullege
Copy the code

It’s especially useful for me when working with lists, maps, etc. Because for the project I’m currently working on, the list or map is more likely to be empty than the other fields. In addition, if you do more with these lists/maps, nPES are likely to appear when they are empty.

Let’s say you want to get the name of a class a student is taking, and you don’t use Builder.default on the “classes “list.

final var student1 = Student.builder().build(); System.out.println(student1.getClasses().stream().map(SchoolClass::getName));Copy the code

Throw the NPE.

6.NotNull, NotEmpty, NotBlank annotation

@notnull :” Annotated elements cannot be empty. Accept any type.” ⁴

@notempty :” Annotated elements cannot be empty or empty. The supported types are CharSequence, Collection, Map, and Array. ⁵

NotBlank:” Annotated elements cannot be empty and must contain at least one non-space character. Accept the CharSequence ⁶.

Suppose you have a controller that has a saveStudent() method. You can add the following comments to the Student class when you want the ID, name, and classes fields not to be empty.

@NotNullprivate Long id; @NotEmptyprivate String name; @NotEmptyprivate List<SchoolClass> classes; private Map<Integer, Teacher> teacherMap;Copy the code

If you are using Spring Boot, you can combine these annotations with the @Validated annotation for the API request body, as shown below.

@PostMapping()public void saveStudent(@Validated @RequestBody Student student){ studentService.saveStudent(student); }Copy the code

For example, you have this request.

As you can see, you’ll get a “400 “error, which you’ll see in your application’s console.

DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void com.example.demodemo.controller.StudentController.saveStudent(com.example.demodemo.model.Student) with 2 errors: [Field error in object 'student' on field 'classes': rejected value [null]; codes [NotEmpty.student.classes,NotEmpty.classes,NotEmpty.java.util.List,NotEmpty];  arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.classes,classes]; arguments []; default message [classes]];  default message [must not be empty]] [Field error in object 'student' on field 'id': rejected value [null]; codes [NotNull.student.id,NotNull.id,NotNull.java.lang.Long,NotNull];  arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [student.id,id]; arguments []; default message [id]]; default message [must not be null]] ]Copy the code

If you like, you can capture the MethodArgumentNotValidException, and return a custom error.

Required dependencies.

implementation 'org.springframework.boot:spring-boot-starter-validation'
Copy the code

That’s what I know so far. I’ll try to update this list as I learn more about shorting checks. Sometimes I still need to use the old-fashioned “if else “block for null-value checking, but I try to apply these methods whenever POSSIBLE.

Hope you enjoyed this article.

Refs.

  1. Docs.oracle.com/javase/8/do…
  2. Docs.oracle.com/javase/8/do…
  3. Docs.oracle.com/javase/9/do…
  4. Docs.oracle.com/javaee/7/ap…
  5. Javaee. Making. IO/javaee – spec…
  6. Javaee. Making. IO/javaee – spec…
  7. www.baeldung.com/java-avoid-…
  8. projectlombok.org/