简体   繁体   中英

Java null check on multiple properties with Optionals

What's the most efficient way on java 11 to null check multiple fields from the same object? I was going with optionals but I don't understand how to use them with more fields of the same object

    Map<String, NestedQuery> nested = new HashMap<>();
    if (getSentDate() != null) {
      if (getSentDate().getFrom() != null && getSentDate().getTo() != null) {
        nested.put(...); 
      }
    }
    return nested;

In my case getSentdate() returns an object that has getFrom() and getTo() that are values that may or may not be null

I tried with this but the use of.ifPresent inside an if clause is a big no no

    Map<String, NestedQuery> nested = new HashMap<>();
    Optional.ofNullable(getSentDate())
        .ifPresent(sentDate -> {
          Optional<String> from = Optional.ofNullable(sentDate.getFrom());
          Optional<String> to = Optional.ofNullable(sentDate.getTo());
          if(from.isPresent() && to.isPresent()){
            nested.put(...);
          }
        });
    return nested;

As it has been said in the comments above your original code is actually quite efficient (we probably need some criteria for effectiveness):

if (getSentDate() != null) {
      if (getSentDate().getFrom() != null && getSentDate().getTo() != null) {

However if you really want to use an Optional to eliminate some of the null checks it is enough to use just one:

Optional.ofNullable(getSentDate())
        .filter(sentDate -> Objects.nonNull(sentDate.getFrom()))
        .filter(sentDate -> Objects.nonNull(sentDate.getTo())) 
        .ifPresent(date -> nested.put(...)); 

in this case .ifPresent(date -> nested.put(...)) is executed only when all 3 conditions are met: getSentDate() is not null , sentDate.getFrom() is not null and sentDate.getTo() is not null as well. However we still have a null check and we are "abusing" Objects#nonNull method since:

API Note: This method exists to be used as a Predicate, filter(Objects::nonNull)

An equivalent for this is

Optional.ofNullable(getSentDate())
        .filter(sentDate -> sentDate.getFrom() != null)
        .filter(sentDate -> sentDate.getTo() != null) 
        .ifPresent(date -> nested.put(...)); 

Please note as well that this actually "violates" Optional usage

API Note: Optional is primarily intended for use as a method return type where there is a clear need to represent "no result," and where using null is likely to cause errors.

Try the following, here a NestedQuery has an optional send date, and a SendDate has optional getFrom and getTo values. You can use ifpresent ans ispresent to check if the value is present

private interface SendDate {

Optional<Object> getFrom();

Optional<Object> getTo();
}

private interface NestedQuery {

public Optional<SendDate> getSendDate();
}

private static NestedQuery createNestedQuery() {
return Optional::empty;
}

public static void main(final String[] args) {
final Map<String, NestedQuery> nested = new HashMap<>();
final NestedQuery nestedQuery = createNestedQuery();
nestedQuery.getSendDate().ifPresent(sendDate -> {
    if (sendDate.getFrom().isPresent() && sendDate.getTo().isPresent())
    nested.put("", nestedQuery);
});
System.out.println(nested.toString());
}

Though the conditional expression using && and its short-circuiting behavior is the best you can get while dealing with multiple levels of attributes. Still, for a single level of nesting , you can easily introduce a utility which conforms none of the attributes inside are null.

@SafeVarargs
static <T> boolean noneNull(T... args) {
    return Arrays.stream(args).noneMatch(Objects::isNull);
}

and use it as

if(noneNull(sentDate.getFrom(), sentDate.getTo())) {
    nested.put(...)
}

and notice, there is no involvement of Optional for this which in general is not required for a check of null objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM