Hashtable старше. Он был отправлен уже в JDK 1.0. В 1.2, когда была представлена структура коллекций, Hashtable была определена как проблема, так как она была реализована с синхронизацией всех открытых методов. Это была мера предосторожности, которая необходима только в многопоточных контекстах и в противном случае снижает производительность (некоторые люди указали, что это можно оптимизировать, но YMMV).
К сожалению, невозможно было просто удалить синхронизацию, поскольку некоторый код уже полагался на Hashtable, реализованный таким образом. Следовательно, HashMap родился. Пока они занимались этим, они добавили функцию «разрешить пустые значения» и адаптировали ее к общей структуре коллекций.
То же самое произошло со StringBuffer, новая несинхронизированная версия которого называется StringBuilder.
Итак, вкратце: используйте HashMap: это новейшая и наиболее продуманная реализация. Hashtable является наследием. Если вам нужна синхронизированная реализация, вы можете выбрать Hashtable или Collections.synchronizedMap (Map).