1

I'm getting a very weird scenario for a for loop.

I'm running the following code:

List<Id> conId = new List<Id>();
List<Customer__c> customers = new List<Customer__c>(); 
customers = [SELECT Id FROM Customer__c WHERE IsValid = false  AND Contact__c != null];
for(Customer__c cust : customers){
    system.debug(cust.Id); 
    conId.add((cust.Contact__c)); 
}
List<Opportunity> opps = new List<Opportunity>(); 
 opps=[SELECT Id, Customer__c FROM Opportunity WHERE Customer__c IN:conId]; 
if(opps.size() != 0){
for(Opportunity opp : opps){
    System.debug(opp.Customer_Contact__c); 
}
}

This is used in a batch class and I believe it is causing a Null Pointer Exception error that is causing the batch class to fail. When I search for null in the filter of the debug logs on this script, I see VARIABLE_ASSIGNMENT cust | null in the logs. Is this normal, or is my null value in the batch class related to something else?

enter image description here

10
  • Are there any records in your org matching the first query?
    – samdev
    Dec 19, 2019 at 4:01
  • You believe it is causing a null pointer? Do you not get a stack trace?
    – Adrian Larson
    Dec 19, 2019 at 4:17
  • Yes, they are displaying the ids for subsequent ones. Will post screen shot of log.
    – thinker
    Dec 19, 2019 at 5:28
  • 1
    @Thinker I don’t think that the variable assignment null is the issue. If you think you are having null pointer exception you should get something like “Attempt to de-reference a null object” is there anything of such sort? Also are the debug statements being displayed in your logs?
    – samdev
    Dec 19, 2019 at 12:30
  • 1
    @thinker, From the screenshot, I see that there is 'opp' in it, which means the code ran until the second for loop without any issues so the issue might be with the second for loop. Also you are using "opp.Customer_Contact__c" but in the Opportunity query you have not added that. you should add the field to the query. It is also better to check if there is anything in the field or not like String.isNotBlank(opp.Customer_Contact__c) before the debug statement so that you can avoid the null exception. Can you also add a screenshot of the null exception from the logs?
    – samdev
    Dec 19, 2019 at 14:50

2 Answers 2

1

This is absolutely normal behavior. If I am not mistaken, for-each loops work with an iterator, so with every loop it tries to get the next element until it hits the end. That is why you are seeing the null variable assignment.

Example from my org:
I just executed these 4 lines:

List<Account> accs = [SELECT Id FROM Account];
for (Account a : accs) {
    System.debug(a);
}

The output was(the last few lines):

11:28:31.1 (18100074)|VARIABLE_SCOPE_BEGIN|[2]|a|Account|true|false
11:28:31.1 (18120892)|VARIABLE_ASSIGNMENT|[2]|a|{"Id":"0014E000015yGYfQAM","RecordTypeId":"012w0000000QFbFAAW"}|0x4f3d8651
11:28:31.1 (18128728)|STATEMENT_EXECUTE|[2]
11:28:31.1 (18130813)|STATEMENT_EXECUTE|[3]
11:28:31.1 (18172773)|USER_DEBUG|[3]|DEBUG|Account:{Id=0014E000015yGYfQAM, RecordTypeId=012w0000000QFbFAAW}
11:28:31.1 (18199138)|HEAP_ALLOCATE|[2]|Bytes:5
11:28:31.1 (18218563)|HEAP_ALLOCATE|[2]|Bytes:12
11:28:31.1 (18229871)|VARIABLE_SCOPE_BEGIN|[2]|a|Account|true|false
11:28:31.1 (18250943)|VARIABLE_ASSIGNMENT|[2]|a|{"Id":"0014E000015yGYpQAM","RecordTypeId":"012w0000000QFbFAAW"}|0x41f2dc71
11:28:31.1 (18258889)|STATEMENT_EXECUTE|[2]
11:28:31.1 (18261042)|STATEMENT_EXECUTE|[3]
11:28:31.1 (18302673)|USER_DEBUG|[3]|DEBUG|Account:{Id=0014E000015yGYpQAM, RecordTypeId=012w0000000QFbFAAW}
11:28:31.1 (18329220)|HEAP_ALLOCATE|[2]|Bytes:5
11:28:31.1 (18352372)|VARIABLE_ASSIGNMENT|[2]|a|null|

If you do not want to see these null variable assignments, you can use a simple loop with a counter:

List<Account> accs = [SELECT Id FROM Account];
for (Integer i = 0; i < accs.size(); i++) {
    Account a = accs[i];
    System.debug(a);
}
1
  • After posting, I was thinking about it more and wondered if it was standard behavior. This helps confirm it. Thanks.
    – thinker
    Dec 19, 2019 at 13:36
0

Its always a best practice to add size() check if you're trying to retrieve bulk records using IN. Your list of contact ids might not have records and hence it might fetch all Opportunities. Refer updated code below:

List<Id> conId = new List<Id>();
List<Customer__c> customers = new List<Customer__c>(); 
customers = [SELECT Id FROM Customer__c WHERE IsValid = false  AND Contact__c != null];
for(Customer__c cust : customers){
    system.debug(cust.Id); 
    conId.add((cust.Contact__c)); 
}

List<Opportunity> opps = new List<Opportunity>(); 
// added a size check
if (conId.size () > 0) {
    opps=[SELECT Id, Customer__c FROM Opportunity WHERE Customer__c IN:conId]; 
    if(opps.size() != 0){
        for(Opportunity opp : opps){
            System.debug(opp.Customer_Contact__c); 
        }
    }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .