Is there a better way of handling multiple null checks in Java?

You can go for a Stream.of and then filter as:

return Stream.of(p1, p2, p3).filter(Objects::nonNull)
                            .map(this::getSuperProduct)
                            .collect(Collectors.toSet());

Here is a way to do it using Optional, not much longer than other answers since each Product object needs to be created anyway.

Set<Product> getallProducts() {
    Set<SuperProducts> superProducts = new HashSet<>;

    Optional.ofNullable(getProduct(brand, price))
        .ifPresent(prod -> superProducts.add(new SuperProduct(prod)));
    Optional.ofNullable(getProduct(brand, price, location))
        .ifPresent(prod -> superProducts.add(new SuperProduct(prod)));
    Optional.ofNullable(getProduct(brand, price, qty))
        .ifPresent(prod -> superProducts.add(new SuperProduct(prod)));

    return superProducts;
}

If you are looking for the most performant way of doing this, stick with the way that your are currently doing it. Your solution is verbose, but probably as efficient as it can be. And there is no doubt that your code is easier to understand than the other alternatives.

If you are looking for solutions that use fewer lines of code, you can implement this using streams and filters, or by creating an array or list of the Product references and iterating. However, these solutions all entail creating temporary data structures and are substantially less efficient.


Note that if the getSuperProduct(p) call is inlined by the JIT compiler, then it may be able to optimize away the implicit test for null that occurs in the call.


Also, I would like to if checking for null each time is expensive than adding to list and iterating through it?

I think that you will find the reverse is the case. You will need to do the null checks in either case (or not ... see above). When you try to use a list, array or stream, you have the overhead of creating the data structure (one or more new heap objects to create and initialize), and you have overhead of testing when you have gotten to the end of the list/array/stream.


One final thing to note is that the efficiency of code like this is often immaterial. We are probably talking about a difference of a less than 100 instructions; i.e. less than 1 microsecond difference. It is probably trivial compared with the rest of what the application is doing.

Tags:

Java

Java 8