Multiple null checks in Java 8

14,412

Solution 1

You may do it like so:

String s = Stream.of(str1, str2, str3)
    .filter(Objects::nonNull)
    .findFirst()
    .orElse(str4);

Solution 2

How about ternary conditional operator?

String s = 
    str1 != null ? str1 : 
    str2 != null ? str2 : 
    str3 != null ? str3 : str4
;

Solution 3

You can also use a loop:

String[] strings = {str1, str2, str3, str4};
for(String str : strings) {
    s = str;
    if(s != null) break;
}

Solution 4

Current answers are nice but you really should put that in a utility method:

public static Optional<String> firstNonNull(String... strings) {
    return Arrays.stream(strings)
            .filter(Objects::nonNull)
            .findFirst();
}

That method has been in my Util class for years, makes code much cleaner:

String s = firstNonNull(str1, str2, str3).orElse(str4);

You can even make it generic:

@SafeVarargs
public static <T> Optional<T> firstNonNull(T... objects) {
    return Arrays.stream(objects)
            .filter(Objects::nonNull)
            .findFirst();
}

// Use
Student student = firstNonNull(student1, student2, student3).orElseGet(Student::new);

Solution 5

I use a helper function, something like

T firstNonNull<T>(T v0, T... vs) {
  if(v0 != null)
    return v0;
  for(T x : vs) {
    if (x != null) 
      return x;
  }
  return null;
}

Then this kind of code can be written as

String s = firstNonNull(str1, str2, str3, str4);
Share:
14,412

Related videos on Youtube

sparker
Author by

sparker

Updated on June 16, 2022

Comments

  • sparker
    sparker almost 2 years

    I have the below code which is bit ugly for multiple null checks.

    String s = null;
    
    if (str1 != null) {
        s = str1;
    } else if (str2 != null) {
        s = str2;
    } else if (str3 != null) {
        s = str3;
    } else {
        s = str4;
    }
    

    So I tried using Optional.ofNullable like below, but its still difficult to understand if someone reads my code. what is the best approach to do that in Java 8.

    String s = Optional.ofNullable(str1)
                       .orElse(Optional.ofNullable(str2)
                                       .orElse(Optional.ofNullable(str3)
                                                       .orElse(str4)));
    

    In Java 9, we can use Optional.ofNullablewith OR, But in Java8 is there any other approach ?

    • Naman
      Naman about 5 years
      Java9 or syntax String s = Optional.ofNullable(str1) .or(() -> Optional.ofNullable(str2)) .or(() -> Optional.ofNullable(str3)) .orElse(str4); looks not as good as the Stream.of I would sya.
    • Vishwa Ratna
      Vishwa Ratna about 5 years
      Optional.ofNullable is in Java-8 only, i guess.
    • matbrgz
      matbrgz about 5 years
      This was what the elvis operator should do easily. I think it is a good thing it wasn't introduced as it makes it easier to work with null values which I think is the wrong way to go.
    • Mohamed Anees A
      Mohamed Anees A about 5 years
      I know the user is asking for Java-8 specific solution, but on a general note, I would go with StringUtils.firstNonBlank()
    • Bill K
      Bill K about 5 years
      Problem is, Java 8/streams isn't the best solution for this. That code really smells like a refactor is in order but without more context it's really hard to tell. For starters--why aren't three objects that are probably so closely related not already in a collection?
    • Bill K
      Bill K about 5 years
      @MohamedAneesA would have provided the best answer (as a comment) but didn't specify the source of StringUtils in this case. At any rate, if you HAVE to have these as a bunch of separate strings, coding it as a vargs method like "firstNonBlank" is ideal, the syntax inside will be an array making a simple for-each loop with a return on finding a non-null value trivial and obvious. In this case, java 8 streams are an attractive nuisance. they tempt you to inline and complicate something that should be a simple method/loop.
    • n0rd
      n0rd about 5 years
    • 0xCursor
      0xCursor about 5 years
      Ok, I just have to ask... how did this post get so much activity and so many upvotes, as well as upvoted answers, in a single day?
  • Naman
    Naman about 5 years
    orElse str4 inspite of it being a null actually
  • Stultuske
    Stultuske about 5 years
    actually, he's looking for "the best approach to do this in Java8". This approach can be used in Java8, so it all just depends on what the OP means by "the best", and on which grounds he bases the decision of what is better on.
  • matbrgz
    matbrgz about 5 years
    This. Think in what you need, not what you have.
  • JollyJoker
    JollyJoker about 5 years
    I usually dislike nested ternaries, but this looks pretty clean.
  • pts
    pts about 5 years
    How much is the speed overhead? Creating Stream objects, calling 4 methods, creating temporary arrays ({str1, str2, str3}) look like much slower than a local if or ?:, which the Java runtime can optimize. Is there some Stream-specific optimization in javac and the Java runtime which makes it as fast as ?:? If not, I won't recommend this solution in performance-critical code.
  • Aaron
    Aaron about 5 years
    @pts this is very likely to be slower than ?: code and I'm sure you should avoid it in performance-critical code. It's however much more readable and you should recommend it in non-performance-critical code IMO, which I'm sure makes more than 99% of code.
  • Holger
    Holger about 5 years
    @pts There are no Stream specific optimizations, neither in javac nor in the runtime. This does not preclude the general optimizations, like inlining all of the code, followed by eliminating redundant operations. In principle, the end result could be as efficient as the plain conditional expressions, however, it’s rather unlikely that it ever gets there, as the runtime would spend the necessary effort only on the hottest code paths.
  • Tom Anderson
    Tom Anderson about 5 years
    FWIW, in SQL, this function is called coalesce, so i call it that in my code too. Whether that works for you depends how much you like SQL, really.
  • Cubic
    Cubic about 5 years
    This is a huge pain to parse for anyone who isn't reading nested ternary operators every day.
  • Ravindra Ranwala
    Ravindra Ranwala about 5 years
    @pts The creation and reclamation of small objects whose constructors do little explicit work is cheap, especially on modern JVM implementations. Creating additional objects to enhance the clarity, simplicity, or power of a program is generally a good thing. There's a deep truth about optimization: it is easy to do more harm than good, especially if you optimize prematurely. So unless your application is performance stringent, you can use this approach with out any hesitation.
  • Todd Sewell
    Todd Sewell about 5 years
    If you're going to put it in a utility method you might as well make it efficient.
  • danielp
    danielp about 5 years
    Great solution! To increase readability a little bit I would suggest to add str4 to the parameters of Stream.of(...) and use orElse(null) in the end.
  • Peter Cordes
    Peter Cordes about 5 years
    @Cubic: If you think it's hard to parse, write a comment like // take first non-null of str1..3. Once you know what it does, it becomes easy to see how.
  • walen
    walen about 5 years
    @GustavoSilva Todd probably means that, this being a utility method of mine, there's no point in using Arrays.stream() when I can do the same with a for and a != null, which is more efficient. And Todd would be right. However, when I coded this method I was looking for a way of doing this using Java 8 features, just like OP, so there's that.
  • displayName
    displayName about 5 years
    You have omitted s4 (or str4), which is to supposed be assigned to s in the end, even if it is null.
  • Bill K
    Bill K about 5 years
    @displayName I prefer to never use auto-formatting. It's impossible to teach an editor how to align things like this, much better to do it yourself.
  • Todd Sewell
    Todd Sewell about 5 years
    @GustavoSilva Yeah that's basically it: if you're going to be putting this is a util function concerns about clean code aren't that important anymore, and so you might as well use a faster version.
  • cmaster - reinstate monica
    cmaster - reinstate monica about 5 years
    @Cubic Yet, this is a simple repeated pattern. Once you parsed line 2, you've parsed the entire thing, no matter how many cases are included. And once you are done, you've learned to express a similar selection of ten different cases in a brief, and relatively simple manner. The next time you'll see a ?: ladder, you'll know what it does. (Btw, functional programmers know this as (cond ...) clauses: It's always a guard followed by the appropriate value to use when the guard is true.)
  • tobias_k
    tobias_k about 5 years
    Why the extra v0 parameter?
  • tobias_k
    tobias_k about 5 years
    @nullpointer Or orElseNull, which amounts to the same if str4 is null.
  • Nick
    Nick about 5 years
    @tobias_k The extra parameter when using varargs is the idiomatic way in Java to require 1 or more arguments rather than 0 or more. (See item 53 of Effective Java, Ed. 3., which uses min as an example.) I am less convinced that this is appropriate here.
  • tobias_k
    tobias_k about 5 years
    @Nick Yes, I guessed as much, but the function would work just as well (in fact behave exactly the same) without it.
  • Michael Anderson
    Michael Anderson about 5 years
    One of the key reasons for passing an extra first argument is to be explicit about the behaviour when passed an array. In this case, I want firstNonNull(arr) to return arr if it is not null. If it was firstNonNull(T... vs) it would instead return the first non-null entry in arr.
  • Vishwa Ratna
    Vishwa Ratna about 5 years
    here findFirst() and findAny() will return the same, what if we have more than one not null;
  • Alvin Thompson
    Alvin Thompson about 5 years
    I guess I've been programming before jdk 8 came out for too long, but this doesn't seem any more readable to me. It's just different. It does have an advantage that the number of lines is (more or less) fixed regardless of the number of items to check.
  • Chauyan
    Chauyan about 5 years
    Pretty nice answer. Thanks for sharing