How to avoid null checking in Java?

后端 未结 30 3272
失恋的感觉
失恋的感觉 2020-11-21 04:43

I use object != null a lot to avoid NullPointerException.

Is there a good alternative to this?

For example I often use:



        
30条回答
  •  时光说笑
    2020-11-21 05:40

    This is a very common problem for every Java developer. So there is official support in Java 8 to address these issues without cluttered code.

    Java 8 has introduced java.util.Optional. It is a container that may or may not hold a non-null value. Java 8 has given a safer way to handle an object whose value may be null in some of the cases. It is inspired from the ideas of Haskell and Scala.

    In a nutshell, the Optional class includes methods to explicitly deal with the cases where a value is present or absent. However, the advantage compared to null references is that the Optional class forces you to think about the case when the value is not present. As a consequence, you can prevent unintended null pointer exceptions.

    In above example we have a home service factory that returns a handle to multiple appliances available in the home. But these services may or may not be available/functional; it means it may result in a NullPointerException. Instead of adding a null if condition before using any service, let's wrap it in to Optional.

    WRAPPING TO OPTION

    Let's consider a method to get a reference of a service from a factory. Instead of returning the service reference, wrap it with Optional. It lets the API user know that the returned service may or may not available/functional, use defensively

    public Optional getRefrigertorControl() {
          Service s = new  RefrigeratorService();
           //...
          return Optional.ofNullable(s);
       }
    

    As you see Optional.ofNullable() provides an easy way to get the reference wrapped. There are another ways to get the reference of Optional, either Optional.empty() & Optional.of(). One for returning an empty object instead of retuning null and the other to wrap a non-nullable object, respectively.

    SO HOW EXACTLY IT HELPS TO AVOID A NULL CHECK?

    Once you have wrapped a reference object, Optional provides many useful methods to invoke methods on a wrapped reference without NPE.

    Optional ref = homeServices.getRefrigertorControl();
    ref.ifPresent(HomeServices::switchItOn);
    

    Optional.ifPresent invokes the given Consumer with a reference if it is a non-null value. Otherwise, it does nothing.

    @FunctionalInterface
    public interface Consumer
    

    Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, Consumer is expected to operate via side-effects. It is so clean and easy to understand. In the above code example, HomeService.switchOn(Service) gets invoked if the Optional holding reference is non-null.

    We use the ternary operator very often for checking null condition and return an alternative value or default value. Optional provides another way to handle the same condition without checking null. Optional.orElse(defaultObj) returns defaultObj if the Optional has a null value. Let's use this in our sample code:

    public static Optional get() {
        service = Optional.of(service.orElse(new HomeServices()));
        return service;
    }
    

    Now HomeServices.get() does same thing, but in a better way. It checks whether the service is already initialized of not. If it is then return the same or create a new New service. Optional.orElse(T) helps to return a default value.

    Finally, here is our NPE as well as null check-free code:

    import java.util.Optional;
    public class HomeServices {
        private static final int NOW = 0;
        private static Optional service;
    
    public static Optional get() {
        service = Optional.of(service.orElse(new HomeServices()));
        return service;
    }
    
    public Optional getRefrigertorControl() {
        Service s = new  RefrigeratorService();
        //...
        return Optional.ofNullable(s);
    }
    
    public static void main(String[] args) {
        /* Get Home Services handle */
        Optional homeServices = HomeServices.get();
        if(homeServices != null) {
            Optional refrigertorControl = homeServices.get().getRefrigertorControl();
            refrigertorControl.ifPresent(HomeServices::switchItOn);
        }
    }
    
    public static void switchItOn(Service s){
             //...
        }
    }
    

    The complete post is NPE as well as Null check-free code … Really?.

提交回复
热议问题