1 of 3

Trying to determine why a slight code change caused a large performance gain

I'm currently refactoring some old code of mine that I had done a few years ago, where it takes in two Lists to compare their contents, and then return the mapped contents that were matched. With 750 items for potential needles, and over 25000 items as the haystack, the original code took about 22-25 seconds to process. After a bit of refactoring however I was able to reduce it to just over a second. What I'm wondering is what the difference is that would account for such a jump in performance?

Here's the original code

        Map<String, ArrayList<TreeMap<String, String>>> map = new TreeMap<String, ArrayList<TreeMap<String, String>>>();

        String charsToFilter = "[" + Pattern.quote("_-") + "]";

        for (int i = 0 ; i < baseDataArray.size() ; i++) {
            String currentProduct = baseDataArray.get(i).get("product_name").replaceAll(charsToFilter, " ").toLowerCase();

            for (int j = 0 ; j < inventoryArray.size() ; j++) {
                String currentListing = inventoryArray.get(j).get("title").replaceAll(charsToFilter, " ").toLowerCase();

                if (currentListing.contains(currentProduct)) {
                    ArrayList<TreeMap<String, String>> currentListingArray = new ArrayList<TreeMap<String, String>>();
                    TreeMap<String, String> currentListingMap = new TreeMap<String, String>();

                    for (Map.Entry<String, String> keyValue : inventoryArray.get(j).entrySet()) {
                        currentListingMap.put(keyValue.getKey(), keyValue.getValue());
                    }

                    currentListingArray.add(currentListingMap);

                    if (map.get(currentProduct) == null) {                      
                        map.put(currentProduct, currentListingArray);
                    } else {
                        map.get(currentProduct).add(currentListingMap);
                    }
                }
            }
        }

return map;

And here's the new code:

Map<String, ArrayList<TreeMap<String, String>>> map = new TreeMap<String, ArrayList<TreeMap<String, String>>>();

        String charsToFilter = "[" + Pattern.quote("_-") + "]";

ArrayList<String> productNameArray = new ArrayList<String>();

        for (Map<String, String> baseDataItem : baseDataArray) {
            productNameArray.add(baseDataItem.get("product_name").replaceAll(charsToFilter, " ").toLowerCase());
        }

        for (Map<String, String> inventoryItem : inventoryArray) {
            String processedInventoryItem = inventoryItem.get("title").replaceAll(charsToFilter, " ").toLowerCase(); //moving this to the for loop below increase execution time by 100%

            for (String productName : productNameArray) {
                if (processedInventoryItem.contains(productName)) {
                    ArrayList<TreeMap<String, String>> currentListingArray = new ArrayList<TreeMap<String, String>>();
                    TreeMap<String, String> currentListingMap = new TreeMap<String, String>();

                    for (Map.Entry<String, String> keyValue : inventoryItem.entrySet()) {
                        currentListingMap.put(keyValue.getKey(), keyValue.getValue());
                    }

                    currentListingArray.add(currentListingMap);

                    if (map.get(productName) == null) {                     
                        map.put(productName, currentListingArray);
                    } else {
                        map.get(productName).add(currentListingMap);
                    }

                    break;
                }
            }
        }

        return map;

There's some differences such as going from for to foreach loops, but nothing that I can see that would make such a change. Anyone have any thoughts?