I'm trying to implement the trigger framework outlined here:

The triggerhandler methods take lists or maps of sObjects as their inputs. In his example he casts list <sObject> as list <Account> by doing:

public void BeforeInsert(List<SObject> newItems) 
        for (Account acc : (List<Account>)newItems)

What is the equivalent for:

public void AfterInsert(Map<Id, SObject> newItems) {
for (opporutnity opp: (........).values()

3 Answers 3


The .values() method will return a list of sObjects, which means that you can simply follow the same scenario and cast the list to a concrete sObject type:

for (Opportunity opp : (List <Opportunity>)newItems.values())

As long as all the values are of type "Opportunity" and you know that for sure.

The alternative way is to work with generic sObjects the whole time:

for (sObject opp : newItems.values())

Read more about dynamic apex

  • 4
    Actually, you can cast it only if the actual object contains a Map<Id, Opportunity>; if it's any other type, expect a runtime exception instead. You can't explicitly assign a Map<Id, SObject> to a Map<Id, Opportunity>, even if it's empty or only contains opportunities.
    – sfdcfox
    Jan 14, 2016 at 0:22
  • @sfdcfox should I put the assignment in a try/catch block? Jan 14, 2016 at 4:42
  • @krewllobster No, just make sure you're using the right type to begin with. Normally you'll know what object you're working on. That is one of the drawbacks of accepting a generic SObject list instead of a specific subtype. Just make sure that if you're in an opportunity trigger, you don't try to cast to a list of accounts or something, and you'll be fine.
    – sfdcfox
    Jan 14, 2016 at 4:47
  • @sfdcfox I'm working on an 'after update' trigger and need to compare old and new values. I'm now feeling like I need to cast the opportunity lists, then rebuild two opportunity maps? Then I can say: for(opportunity o: newopps.values) {if(o.value != oldvalues.get(o.id).value) {logic}} Jan 14, 2016 at 18:18
  • @krewllobster I have found that maps are relatively expensive compared to list access, so I'd recommend using Trigger.new/Trigger.old, and iterating over the values like this: for(Integer index = 0, size = Trigger.new.size(); index < size; index++) { Opportunity o = Trigger.old[index], n = Trigger.new[index]; if(n.value != o.value) { ... } }.
    – sfdcfox
    Jan 14, 2016 at 18:50

I know this is old, but still pulls up as the result via a google search. So I'm going to post something I have had luck with.

If you know what sObject you are converting into, I've had success doing this:

objList //we'll say this is a Map<Id, sObject> where the sObject is an Opportunity
 List<Opportunity> oppList = objList.values();

Or looping:

   for(Opportunity o : objList.values())

It's a little different than the previous answer given, so I hope someone finds it useful.

Edit: Apologies, realized this is for Map to Map. However I'll leave this because in some situations converting to a list from a Map will be beneficial as it should have already removed dups from being in a map, and then you can iterate through the list or perform DML on it.


You can iterate over a hash map using:

public void AfterInsert(Map<Id, SObject> newItems) {
    for (Id key: newItems.keySet())
        Opportunity opp = (Opportunity)newItems.get(key);
        //do something with your opp

So basically what you are doing here is:

  • using the keySet() method on the Map to get an iterator (so you're looping on the keys)
  • Then using that key, you get that particular SObject from your map (using the get() method)
  • Then you are type casting from SObject directly to an Opportunity class

There's an example here: Iterating over a map (Apex)

  • 5
    I would specifically avoid doing this: using a map when a list would suffice would waste about 25ms per item in the list. That's a pretty stiff penalty.
    – sfdcfox
    Jan 14, 2016 at 0:24
  • Crikey. That's a heap. Poor heap. Oct 2, 2017 at 1:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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