Dictionary<TKey, TValue> finding key: try/catch vs TryGetValue

Today I saw some code where the developer accessed a dictionary like this:

  1. void Foo(int keyToFindInDictionary)
  2. {
  3.     Dictionary<int, string> dictionary = new Dictionary<int, string>();
  4.  
  5.     try
  6.     {
  7.         DoSomethingWithTheResult(dictionary[keyToFindInDictionary]);
  8.     }
  9.     catch (KeyNotFoundException)
  10.     {
  11.         // fallback
  12.     }
  13. }
  14.  
  15. private void DoSomethingWithTheResult(string s)
  16. {
  17.     // do something
  18. }

As you can see he catches the exception to handle the fact that the given key was not found in the dictionary.

I told him that there was a better way, i.e. Dictionary<TKey, TValue>.TryGetValue.

And then the curious part of me started thinking, how much better is it? Is it faster? Slower?

So I wrote the following small piece of code to test my statement that TryGetValue is better than catching the KeyNotFoundException.

  1. namespace DictionaryTryGetValueVersusException
  2. {
  3.     using System;
  4.     using System.Collections.Generic;
  5.     using System.Diagnostics;
  6.  
  7.     internal class Program
  8.     {
  9.         private static void Main()
  10.         {
  11.             // create a dictionary with some values
  12.             Dictionary<string, string> dictionary = new Dictionary<string, string>();
  13.  
  14.             // add 10,000 items
  15.             for (int i = 0; i < 10000; i++)
  16.             {
  17.                 if (i == 5000)
  18.                 {
  19.                     // skip
  20.                     continue;
  21.                 }
  22.  
  23.                 dictionary.Add(string.Format("Key{0}", i), string.Format("Value{0}", i));
  24.             }
  25.  
  26.             Stopwatch stopwatch = new Stopwatch();
  27.  
  28.             stopwatch.Start();
  29.  
  30.             const string keyToFindInDictionary = "Key5000";
  31.  
  32.             for (int i = 0; i < 10000; i++)
  33.             {
  34.                 // 5000 does not exist
  35.                 try
  36.                 {
  37.                     // execute a method on the variable, so that he compiler doesn't optimize it.
  38.                     dictionary[keyToFindInDictionary];
  39.                 }
  40.                 catch (Exception)
  41.                 {
  42.                     // ignore
  43.                 }
  44.             }
  45.  
  46.             stopwatch.Stop();
  47.             Console.WriteLine("Dictionary lookup with try/catch took: {0}", stopwatch.ElapsedTicks);
  48.  
  49.             stopwatch.Restart();
  50.  
  51.             for (int i = 0; i < 10000; i++)
  52.             {
  53.                 string notFound;
  54.                 // 5000 does not exist
  55.                 dictionary.TryGetValue(keyToFindInDictionary, out notFound);
  56.             }
  57.  
  58.             stopwatch.Stop();
  59.             Console.WriteLine("Dictionary lookup with TryGetValue took: {0}", stopwatch.ElapsedTicks);
  60.  
  61.             Console.WriteLine("Done, press enter to exit");
  62.             Console.ReadLine();
  63.         }
  64.     }
  65. }

As you can see we add 10,000 items to the dictionary, skipping the 5000th item, and then we do a lookup in the dictionary, 10,000 times, on the key that doesn’t exist, to measure the performance difference between the 2 previously discussed methods.

To run this test I did a Release Build in Visual Studio 2010, .NET 4.0, Any CPU, and this is the result:

Results

Dictionary lookup with try/catch took: 1069625
Dictionary lookup with TryGetValue took: 864
Done, press enter to exit

As you can see there is a HUGE difference. The TryGetValue-way was about 1237 faster!

Exception throwing is very heavy! Don’t forget that. It doesn’t mean that you need to program without exceptions, but when you EXPECT that a Key is not present in a given dictionary, don’t use the exception. Use the TryGetValue. If you always expect it to be there then it’s normal to catch the exception, because it’s exceptional that the key was not found.

PS: I tried the code again by skipping the 9999th item, and the results were about the same, take or leave a few milliseconds. So searching in the dictionary is very performant (close to O(1), as written in the Remarks section on this page.)

One thought on “Dictionary<TKey, TValue> finding key: try/catch vs TryGetValue”

  1. Thanks! I was just wondering why my hash table accesses were slow, and figured it might be because of exception handlers. You confirmed it for me and saved a lot of time.

Comments are closed.