10

I'm obviously missing something here.
I'm trying to remove a key-value from a map using the "remove" function but the remove function returns null, as if the key doesn't exist in the map.
As you can see from the debug log, the map contains the key and the "get" function works for this key on this map.
The list is a list of the type of the value in the map (Tier__c). I tried creating a local Tier__c variable that will get the result of the remove but the remove function still return null.
Please see the code and the debug log below.

Code:

//Go through active tiers.
for(integer i = 0; i < map_plIdToTiers.get(priceListId).size(); i++)
{
    system.debug('Gad --> map_plIdToFTiers.get(priceListId).containsKey(i+1): ' + map_plIdToFTiers.get(priceListId).containsKey(i+1));
    //Check if we don't have future tier for this tier sequence.
    if(!map_plIdToFTiers.get(priceListId).containsKey(i+1))
    {
        system.debug('Gad --> i+1: ' + (i+1));
        system.debug('Gad --> map_plIdToTiers.get(priceListId): ' + map_plIdToTiers.get(priceListId));
        system.debug('Gad --> map_plIdToTiers.get(priceListId).get(i+1): ' + map_plIdToTiers.get(priceListId).get(i+1));
        system.debug('Gad --> map_plIdToTiers.get(priceListId).containsKey(i+1): ' + map_plIdToTiers.get(priceListId).containsKey(i+1));
        system.debug('Gad --> lst_tiersToDelete before: ' + lst_tiersToDelete);
        //Remove the active tier and rate for this tier sequence.
        lst_tiersToDelete.add(map_plIdToTiers.get(priceListId).remove(i+1));
        lst_ratesToDelete.add(map_plIdToRates.get(priceListId).remove(i+1));
        system.debug('Gad --> map_plIdToTiers.get(priceListId).get(i+1): ' + map_plIdToTiers.get(priceListId).get(i+1));
        system.debug('Gad --> lst_tiersToDelete after: ' + lst_tiersToDelete);
    }
}

Debug log:

21:57:11.028 (6028457431)|USER_DEBUG|[344]|DEBUG|Gad --> map_plIdToFTiers.get(priceListId).containsKey(i+1): false
21:57:11.028 (6028461927)|SYSTEM_METHOD_EXIT|[344]|System.debug(ANY)
21:57:11.028 (6028473555)|SYSTEM_METHOD_ENTRY|[346]|Map<Id,Map<Decimal,Future_Tier__c>>.get(Object)
21:57:11.028 (6028489242)|SYSTEM_METHOD_EXIT|[346]|Map<Id,Map<Decimal,Future_Tier__c>>.get(Object)
21:57:11.028 (6028500906)|SYSTEM_METHOD_ENTRY|[346]|Map<Decimal,Future_Tier__c>.containsKey(Object)
21:57:11.028 (6028519955)|SYSTEM_METHOD_EXIT|[346]|Map<Decimal,Future_Tier__c>.containsKey(Object)
21:57:11.028 (6028549042)|SYSTEM_METHOD_ENTRY|[348]|String.valueOf(Object)
21:57:11.028 (6028577758)|SYSTEM_METHOD_EXIT|[348]|String.valueOf(Object)
21:57:11.028 (6028597392)|SYSTEM_METHOD_ENTRY|[348]|System.debug(ANY)
21:57:11.028 (6028602961)|USER_DEBUG|[348]|DEBUG|Gad --> i+1: 3
21:57:11.028 (6028607397)|SYSTEM_METHOD_EXIT|[348]|System.debug(ANY)
21:57:11.028 (6028631145)|SYSTEM_METHOD_ENTRY|[349]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.028 (6028659330)|SYSTEM_METHOD_EXIT|[349]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.028 (6028678060)|SYSTEM_METHOD_ENTRY|[349]|String.valueOf(Object)
21:57:11.028 (6028791518)|SYSTEM_METHOD_EXIT|[349]|String.valueOf(Object)
21:57:11.028 (6028808625)|SYSTEM_METHOD_ENTRY|[349]|System.debug(ANY)
21:57:11.028 (6028814224)|USER_DEBUG|[349]|DEBUG|Gad --> map_plIdToTiers.get(priceListId): {1=Tier__c:{Id=a1Hm0000000HYvAEAW, RecordTypeId=012m00000000QuiAAE, Price_List__c=a0mm0000006xFhrAAE, Tier_Seq__c=1}, 2=Tier__c:{Id=a1Hm0000000HYvBEAW, RecordTypeId=012m00000000QuiAAE, Price_List__c=a0mm0000006xFhrAAE, Tier_Seq__c=2}, 3=Tier__c:{Id=a1Hm0000000HYvCEAW, RecordTypeId=012m00000000QuiAAE, Price_List__c=a0mm0000006xFhrAAE, Tier_Seq__c=3}}
21:57:11.028 (6028821485)|SYSTEM_METHOD_EXIT|[349]|System.debug(ANY)
21:57:11.028 (6028845036)|SYSTEM_METHOD_ENTRY|[350]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.028 (6028874361)|SYSTEM_METHOD_EXIT|[350]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.028 (6028889328)|SYSTEM_METHOD_ENTRY|[350]|Map<Decimal,Tier__c>.get(Object)
21:57:11.028 (6028913686)|SYSTEM_METHOD_EXIT|[350]|Map<Decimal,Tier__c>.get(Object)
21:57:11.028 (6028931030)|SYSTEM_METHOD_ENTRY|[350]|String.valueOf(Object)
21:57:11.028 (6028987899)|SYSTEM_METHOD_EXIT|[350]|String.valueOf(Object)
21:57:11.029 (6029004379)|SYSTEM_METHOD_ENTRY|[350]|System.debug(ANY)
21:57:11.029 (6029010773)|USER_DEBUG|[350]|DEBUG|Gad --> map_plIdToTiers.get(priceListId).get(i+1): Tier__c:{Id=a1Hm0000000HYvCEAW, RecordTypeId=012m00000000QuiAAE, Price_List__c=a0mm0000006xFhrAAE, Tier_Seq__c=3}
21:57:11.029 (6029016523)|SYSTEM_METHOD_EXIT|[350]|System.debug(ANY)
21:57:11.029 (6029039967)|SYSTEM_METHOD_ENTRY|[351]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.029 (6029068771)|SYSTEM_METHOD_EXIT|[351]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.029 (6029083751)|SYSTEM_METHOD_ENTRY|[351]|Map<Decimal,Tier__c>.containsKey(Object)
21:57:11.029 (6029104409)|SYSTEM_METHOD_EXIT|[351]|Map<Decimal,Tier__c>.containsKey(Object)
21:57:11.029 (6029121190)|SYSTEM_METHOD_ENTRY|[351]|String.valueOf(Object)
21:57:11.029 (6029135991)|SYSTEM_METHOD_EXIT|[351]|String.valueOf(Object)
21:57:11.029 (6029149087)|SYSTEM_METHOD_ENTRY|[351]|System.debug(ANY)
21:57:11.029 (6029154444)|USER_DEBUG|[351]|DEBUG|Gad --> map_plIdToTiers.get(priceListId).containsKey(i+1): true
21:57:11.029 (6029158941)|SYSTEM_METHOD_EXIT|[351]|System.debug(ANY)
21:57:11.029 (6029183847)|SYSTEM_METHOD_ENTRY|[352]|String.valueOf(Object)
21:57:11.029 (6029216859)|SYSTEM_METHOD_EXIT|[352]|String.valueOf(Object)
21:57:11.029 (6029232089)|SYSTEM_METHOD_ENTRY|[352]|System.debug(ANY)
21:57:11.029 (6029237392)|USER_DEBUG|[352]|DEBUG|Gad --> lst_tiersToDelete before: ()
21:57:11.029 (6029241814)|SYSTEM_METHOD_EXIT|[352]|System.debug(ANY)
21:57:11.029 (6029261326)|SYSTEM_METHOD_ENTRY|[354]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.029 (6029288955)|SYSTEM_METHOD_EXIT|[354]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.029 (6029305103)|SYSTEM_METHOD_ENTRY|[354]|Map<Decimal,Tier__c>.remove(Object)
21:57:11.029 (6029329327)|SYSTEM_METHOD_EXIT|[354]|Map<Decimal,Tier__c>.remove(Object)
21:57:11.029 (6029342760)|SYSTEM_METHOD_ENTRY|[354]|List<Tier__c>.add(Object)
21:57:11.029 (6029359781)|SYSTEM_METHOD_EXIT|[354]|List<Tier__c>.add(Object)
21:57:11.029 (6029378260)|SYSTEM_METHOD_ENTRY|[355]|Map<Id,Map<Decimal,Country_Rate__c>>.get(Object)
21:57:11.029 (6029405400)|SYSTEM_METHOD_EXIT|[355]|Map<Id,Map<Decimal,Country_Rate__c>>.get(Object)
21:57:11.029 (6029421065)|SYSTEM_METHOD_ENTRY|[355]|Map<Decimal,Country_Rate__c>.remove(Object)
21:57:11.029 (6029440147)|SYSTEM_METHOD_EXIT|[355]|Map<Decimal,Country_Rate__c>.remove(Object)
21:57:11.029 (6029452729)|SYSTEM_METHOD_ENTRY|[355]|List<Country_Rate__c>.add(Object)
21:57:11.029 (6029466602)|SYSTEM_METHOD_EXIT|[355]|List<Country_Rate__c>.add(Object)
21:57:11.029 (6029485126)|SYSTEM_METHOD_ENTRY|[356]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.029 (6029512135)|SYSTEM_METHOD_EXIT|[356]|Map<Id,Map<Decimal,Tier__c>>.get(Object)
21:57:11.029 (6029526365)|SYSTEM_METHOD_ENTRY|[356]|Map<Decimal,Tier__c>.get(Object)
21:57:11.029 (6029549457)|SYSTEM_METHOD_EXIT|[356]|Map<Decimal,Tier__c>.get(Object)
21:57:11.029 (6029566591)|SYSTEM_METHOD_ENTRY|[356]|String.valueOf(Object)
21:57:11.029 (6029628506)|SYSTEM_METHOD_EXIT|[356]|String.valueOf(Object)
21:57:11.029 (6029644890)|SYSTEM_METHOD_ENTRY|[356]|System.debug(ANY)
21:57:11.029 (6029650390)|USER_DEBUG|[356]|DEBUG|Gad --> map_plIdToTiers.get(priceListId).get(i+1): Tier__c:{Id=a1Hm0000000HYvCEAW, RecordTypeId=012m00000000QuiAAE, Price_List__c=a0mm0000006xFhrAAE, Tier_Seq__c=3}
21:57:11.029 (6029656261)|SYSTEM_METHOD_EXIT|[356]|System.debug(ANY)
21:57:11.029 (6029681427)|SYSTEM_METHOD_ENTRY|[357]|String.valueOf(Object)
21:57:11.029 (6029711625)|SYSTEM_METHOD_EXIT|[357]|String.valueOf(Object)
21:57:11.029 (6029725969)|SYSTEM_METHOD_ENTRY|[357]|System.debug(ANY)
21:57:11.029 (6029731195)|USER_DEBUG|[357]|DEBUG|Gad --> lst_tiersToDelete after: (null)
  • Can you add the Map definition to the code sample please. – Daniel Ballinger Jul 13 '15 at 19:42
  • At no point does your debug log show that 1st_tiersToDelete has values within. Also, when you do your initial add to 1st_tiersToDelete, you have a remove command which I believe returns NULL. Do the removal of i+1 the line before and then add the map_plIdToTiers.get(priceListId. – techbusinessman Jul 13 '15 at 19:43
  • 2
    Having maps with nearly identical names - map_plIdToTiers and map_plIdToFTiers - is a bad idea because they are nearly impossible to tell apart when reviewing code. Escpecially if the maps have different type content. One allows containsKey - map content - but does the other have list content? – Keith C Jul 13 '15 at 19:46
  • 1. Here are the map definitions: map <Id, map <decimal, Future_Tier__c>> map_plIdToFTiers = new map <Id, map <decimal, Future_Tier__c>>(); map <Id, map <decimal, Tier__c>> map_plIdToTiers = new map <Id, map <decimal, Tier__c>>(); – Dagish Jul 13 '15 at 20:09
  • 2. I'm sorry techbusinessman but i'm not sure i understand your comment. i know that lst_tiersToDelete doesn't have values, that's the problem. i was expecting to get a value in the list from the remove function but it returns null. i can add values to lst_tiersToDelete with get function but i still need to remove the values from the map. – Dagish Jul 13 '15 at 20:13
8

Based on the test below, this appears to be a platform bug when key values are coerced (implicitly converted) to the declared type of the key. (At least for Decimal keys but may affect other types.) The first test method here fails and the second and third ones pass (and comply with the Map contract):

@isTest
private class MapTest {

    @isTest
    static void mixed() {
        Map<Decimal, String> m = new Map<Decimal, String>();
        m.put(8, 'Eight');
        System.assertEquals(true, m.containsKey(8));
        System.assertEquals('Eight', m.remove(8));
        System.assertEquals(false, m.containsKey(8));
    }

    @isTest
    static void decimal() {
        Map<Decimal, String> m = new Map<Decimal, String>();
        m.put(Decimal.valueOf(8), 'Eight');
        System.assertEquals(true, m.containsKey(Decimal.valueOf(8)));
        System.assertEquals('Eight', m.remove(Decimal.valueOf(8)));
        System.assertEquals(false, m.containsKey(Decimal.valueOf(8)));
    }

    @isTest
    static void integer() {
        Map<Integer, String> m = new Map<Integer, String>();
        m.put(8, 'Eight');
        System.assertEquals(true, m.containsKey(8));
        System.assertEquals('Eight', m.remove(8));
        System.assertEquals(false, m.containsKey(8));
    }
}

In e.g. Java a compile error would flag that 8 isn't a BigDecimal and so block the problem at compile time.

So use Integer as the type for the key and make sure the values looked up are all Integer values (or be careful about the type conversion of the values used) as a work-around and raise a case with Salesforce about the bug.

  • 1
  • Thanks for solving the mystery. I'll raise a case about this issue to SF. I hope they won't close it due to the fact i don't have code support. – Dagish Jul 14 '15 at 4:58
  • Salesforce support never disappoints - They closed my case because i don't have developer support. – Dagish Jul 14 '15 at 8:51
  • 1
    @Dagish We do have developer support and I've raised a case containing the above test case. – Keith C Jul 14 '15 at 10:25
0

Normally when I loop through something and remove things from the collection I'm iterating over I reverse the iteration order. E.g.

for(integer i = collection.size(); i >= 0; i--) {
    // Get the indexed value, etc...
    collection.remove(i);
}

This way my index i is always valid, as it will be unaffected by the record that has just been removed.


The first thing I'd do is extract the required collection from the Map once. Then work backwards through that collection.

List<Tier__c> priceListTiers = map_plIdToTiers.get(priceListId);
for(integer i = priceListTiers.size(); i >= 0; i--) {
    Tier__c priceListTier = priceListTiers.get(i);
    //Check if we don't have future tier for this tier sequence.
    // ...
    {
        priceListTiers.remove(i);
    }
}
  • Hi Daniel, thanks for the answer. This workaround might work and if i'll have to, i will use it. It will require to remove all values from the map and additional for loop to insert the values that i need to keep back to the map. But i would really like to understand why the remove function doesn't work. You can clearly see in the debug log that the key exists in the map and that the get function for this key works. Any ideas? – Dagish Jul 13 '15 at 20:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.