[SalesForce] De-reference null object error on Trigger – error only when value is null

I have a trigger and an Account handler. I have an error on record insert.
Trigger calls

Accounthandler.OnAfterInsert(Trigger.new, Trigger.newMap);

Here is a simplified version of the handler top method:

public void OnAfterInsert(Account[] newAccounts, Map<Id, Account> newAccountMap){
    if(!System.isFuture() && !System.isBatch()){
        myMethod(null, newAccounts, null, newAccountMap);
    }
}

Now the method itself:

private void identifyAndGeoCodeAccounts(Account[] oldAccounts, Account[] updatedAccounts, Map<ID, Account> oldAccountMap, Map<ID, Account> newAccountMap){
        Set<Id> ChangedAddressIDs = new Set<Id>();
        for(Account a : updatedAccounts){
            system.debug('evaluating account ' + a);
            if( 
                ( a.BillingCountry != null && oldAccounts == null )

                 // Error happens in line above, saying that a.BillingCountry is null object

                || 
                (
                    a.BillingStreet != oldAccountMap.get(a.id).BillingStreet ||
                    a.BillingCity != oldAccountMap.get(a.id).BillingCity ||
                    a.BillingState != oldAccountMap.get(a.id).BillingState ||
                    a.BillingPostalCode != oldAccountMap.get(a.id).BillingPostalCode ||
                    a.BillingCountry != oldAccountMap.get(a.id).BillingCountry
                )
                || 
                ( //otherstuff ) 
            ) {
                ChangedAddressIDs.add(a.id);
            }
        }
        if(ChangedAddressIDs.size() == 1){
            //dostuff
        } else if(ChangedAddressIDs.size() == 0){
            system.debug('ChangedAddressIDs.sizes = 0');
            return;
        } else {
            //system.debug('ChangedAddressIDs.size > 1');
            //do other stuff
        }
    }

And here is the test code:

    @isTest static void hasGeocode() {
            test.startTest();
            Account a = new Account(name='TestAccount');
            //a.BillingCountry = 'US';
            insert a;
            test.stopTest();
            //other stuff after asynch stuff happens
        }

Pretty straightforward.
When I populate BillingCountry in the test, all is good. When I don't, all fails. I can debug the Account a and I have no problems. It even shows BillingCountry as null.
Any ideas, StackExchangers?

The error is that I'm de-referencing a null object, and it refers specifically to the "a.BillingCountry != null" part. I've isolated it down to that. But a.BillingCountry is included when I debug the Account; even if it is null, my conditional should allow for it to be true, so the first part of the IF clause should be true on insert, so it should add the Id to the Set. But it has an error specifically with a.BillingCountry.

Best Answer

crop1645 is right in that the error is your second major OR grouping. If the first condition is not satisfied, only then will the second condition be evaluated, and you only want that to happen if there is an oldaccounts. You could do this through trigger awareness (which can make it a little harder to unit test), or you can just make sure you don't evaluate it if there are no oldaccounts:

||
(oldaccounts != null &&     
    (a.BillingStreet != oldAccountMap.get(a.id).BillingStreet ||
    a.BillingCity != oldAccountMap.get(a.id).BillingCity ||
    a.BillingState != oldAccountMap.get(a.id).BillingState ||
    a.BillingPostalCode != oldAccountMap.get(a.id).BillingPostalCode ||
    a.BillingCountry != oldAccountMap.get(a.id).BillingCountry))
||
Related Topic