What is Safe Navigation in Apex?

September 16, 2020 by Trieste LaPorte

What is Safe Navigation in Apex?

Salesforce recently talked about a new “Safe Navigation Operator” in the Winter ‘21 release notes. Check it out here.

For many years my friends and I have been waging a light-hearted code review war, and this new feature will end that war once and for all, at least for us.

What’s the war about?

I’ll simplify the situation and describe the most common patterns as two sides. For all examples we’re going to use a String comparison.

The Kessel Alliance likes code to read naturally and in the same order one would describe the code in verbal communications. The Kessel Alliance pattern also tends to represent what you see in the wild, since it is so natural. Here we’re going to stay simple (and not completely safe).

Example:

public static Boolean isStringTheSame (String variableString) {
    String controlString = 'control string';
    
    return variableString.equalsIgnoreCase(controlString);
}

The leader of the Kessel Alliance would never let me hear the end of it if I left it like this. If variableString is null, the above code will throw a Null Pointer Exception (NPE). Members of the Kessel Alliance would surely keep their code NPE safe and write something like this instead:

public static Boolean isStringTheSame (String variableString) {
    String controlString = 'control string';
    
    if (String.isNotBlank(variableString)) {
        return variableString.equalsIgnoreCase(controlString);
    } else {
        return false;
    }
}

The competing pattern, and the one I have classically used, kills two proverbial birds with one stone but can be awkward to read. This pattern comes to us from the Pond Empire.

public static Boolean isStringTheSame (String variableString) {
    String controlString = 'control string';
    
    return controlString.equalsIgnoreCase(variableString);
}

Since we know controlString is never null it’s safe to reference without checking. Even if variableString is null here, the method will safely return false. The above example may not look very weird…. until you write it like this (you should be using constants anyway):

public static Boolean isStringTheSame (String variableString) {
    return 'control string'.equalsIgnoreCase(variableString);
}

There are pros and cons to both approaches. There are also tons of variations and for the sake of this article we don’t need to cover them all. On a side note I think it’s a great idea to respond to the calling code when certain values (like null) are not allowed. Good input checking is good, and a subject for another article.

What’s the big deal?

For the examples so far there is not a huge amount extra work either way. So let’s play with some extreme examples using SObjects.

Kessel Alliance (with safety checks):

public static Boolean isGreatGrandparentAccountSalesforce (Account theAccount) {
    String salesforceAccountName = 'Salesforce';
    if (theAccount != null && 
        theAccount.AccountId != null && 
        theAccount.Account.AccountId != null && 
        theAccount.Account.Account.AccountId != null && 
        String.isNotBlank(theAccount.Account.Account.Account.Name) && 
        theAccount.Account.Account.Account.Name.equalsIgnoreCase(salesforceAccountName)) {
            return true;
    } else {
        return false;
    }
}

Pond Empire:

public static Boolean isGreatGrandparentAccountSalesforce (Account theAccount) {
    String salesforceAccountName = 'Salesforce';
    if (theAccount != null && 
        theAccount.AccountId != null && 
        theAccount.Account.AccountId != null && 
        theAccount.Account.Account.AccountId != null &&  
        salesforceAccountName.equalsIgnoreCase(theAccount.Account.Account.Account.Name)) {
            return true;
    } else {
        return false;
    }
}

As you can see with our extreme example we’re still writing code that’s cumbersome in both cases. That’s where the Safe Navigation Operator shines. Here’s the same method written in a way that makes both the Alliance and the Empire happy.

public static Boolean isGreatGrandparentAccountSalesforce (Account theAccount) {
    String salesforceAccountName = 'Salesforce';
    
    return theAccount?.Account?.Account?.Account?.Name?.equalsIgnoreCase(salesforceAccountName);
}

Big change, right? Again… input checking is worth it. None of these examples represent good input checking or any sort of feedback to the calling code. The way they’re written they make assumptions, and assumptions lead to code that can be difficult to troubleshoot.

Conclusion

That’s about it… I just wanted to point out how cool this feature was. Bonus points for getting to name some nerdy forces after friends.

Thanks go out to Sebastian Kessel at theCodery.io and Mark Pond from CodeScience.com for being good sports. What are we going to argue about now?

Finally, please don’t kill me if this feature comes out and behaves differently than I indicate here. I wrote all of this based entirely on the release notes and have not been able to test it first hand.

If you’re just as passionate about Apex as we are and looking to work with, learn from, and challenge some of the best consultants, click the button below to get in touch with us.

Trieste LaPorte

ABOUT THE AUTHOR

Trieste LaPorte | Technical Architect

Trieste is a Technical Architect with Foglight Solutions and has been breaking the platform for a decade.