Popular Searches
Popular Course Categories
Popular Courses

Exploring Hashtable and Properties

Exploring Hashtable and Properties

Maps, Iterators, and Collection Utilities

Exploring Hashtable and Properties in Java

Course: Core Java Training

Topic: Exploring Hashtable and Properties

Course Link: Core Java Training Course

Demo Link: Register for a Free Course Demo

JustAcademy Website: Visit JustAcademy


1. Introduction

Java provides several classes for storing and managing data as key-value pairs. The Hashtable and Properties classes are two important classes in the Java Collections Framework and the Java utility library. They are useful for understanding legacy collection implementations, configuration management, and applications that need to store settings as strings.

Hashtable stores key-value pairs in a hash table. It is synchronized, meaning its individual methods provide built-in synchronization. It does not permit null keys or null values.

Properties extends Hashtable and is designed primarily for configuration data such as application settings, file paths, database connection parameters, and environment-specific options. Its keys and values are intended to be strings, and it provides methods for loading and saving property data.

2. Learning Objectives

  • Understand the purpose and characteristics of Hashtable.
  • Create, insert, retrieve, update, and remove key-value pairs.
  • Learn how synchronization works in Hashtable.
  • Understand the purpose of the Properties class.
  • Load and save configuration settings using property files.
  • Differentiate Hashtable, Properties, and HashMap.
  • Apply best practices when working with configuration data.

3. What Is Hashtable?

java.util.Hashtable is a legacy collection class that stores elements as key-value pairs. Each key maps to a value, and the hash code of a key helps determine where its entry is stored internally.

It implements the Map interface and provides methods to add, access, update, and remove entries.

Key Characteristics

  • Key-value storage: Each entry contains one key and its associated value.
  • Unique keys: A key can appear only once. Adding the same key again replaces its previous value.
  • No null keys or values: Attempts to insert either a null key or a null value cause a NullPointerException.
  • Synchronized methods: Individual operations are synchronized.
  • Unordered entries: Iteration order is not guaranteed.
  • Legacy class: For most new applications, HashMap or ConcurrentHashMap is generally a better choice, depending on concurrency requirements.

Import Statement

import java.util.Hashtable;

4. Creating a Hashtable

A Hashtable can be created by using its constructor. You can specify the key and value types with generics to improve type safety.

import java.util.Hashtable;

public class HashtableCreation {
    public static void main(String[] args) {
        Hashtable<Integer, String> students = new Hashtable<>();

        students.put(101, "Aarav");
        students.put(102, "Priya");
        students.put(103, "Rahul");

        System.out.println(students);
    }
}

Possible output:

{103=Rahul, 102=Priya, 101=Aarav}

The displayed order may vary because Hashtable does not guarantee insertion order or sorted order.

5. Important Hashtable Methods

Method Purpose Example
put(key, value) Adds an entry or replaces the value for an existing key. table.put(1, "Java");
get(key) Returns the value associated with a key, or null if absent. table.get(1);
remove(key) Removes the entry for a key. table.remove(1);
containsKey(key) Checks whether a key exists. table.containsKey(1);
contains(value) Checks whether a value exists. table.contains("Java");
size() Returns the number of entries. table.size();
isEmpty() Checks whether the table contains no entries. table.isEmpty();
clear() Removes all entries. table.clear();
keys() Returns an enumeration of the keys. table.keys();
elements() Returns an enumeration of the values. table.elements();
getOrDefault(key, defaultValue) Returns the mapped value or a supplied default. table.getOrDefault(9, "Unknown");

6. Adding and Updating Entries

The put() method inserts a new entry or updates an existing entry when the key is already present.

import java.util.Hashtable;

public class HashtablePutExample {
    public static void main(String[] args) {
        Hashtable<String, Integer> scores = new Hashtable<>();

        scores.put("Aarav", 80);
        scores.put("Priya", 92);
        scores.put("Aarav", 88);

        System.out.println(scores.get("Aarav"));
        System.out.println(scores.size());
    }
}

Output:

88
2

The second insertion for the key "Aarav" replaces the previous score. It does not create a duplicate key.

7. Retrieving and Checking Data

Use get() to retrieve a value and containsKey() to check whether a key exists. Since get() returns null when a key is absent, checking containsKey() can help distinguish an absent key from a present mapping in map implementations that permit null values. A Hashtable itself does not permit null values.

import java.util.Hashtable;

public class HashtableLookup {
    public static void main(String[] args) {
        Hashtable<String, String> settings = new Hashtable<>();

        settings.put("language", "Java");
        settings.put("level", "Beginner");

        if (settings.containsKey("language")) {
            System.out.println(settings.get("language"));
        }

        System.out.println(settings.getOrDefault("theme", "Light"));
    }
}

Output:

Java
Light

8. Removing Entries

The remove() method deletes an entry using its key. The clear() method removes every entry from the table.

import java.util.Hashtable;

public class HashtableRemove {
    public static void main(String[] args) {
        Hashtable<Integer, String> items = new Hashtable<>();

        items.put(1, "Keyboard");
        items.put(2, "Mouse");
        items.put(3, "Monitor");

        items.remove(2);

        System.out.println(items.containsKey(2));
        System.out.println(items.size());

        items.clear();
        System.out.println(items.isEmpty());
    }
}

Output:

false
2
true

9. Iterating Through a Hashtable

You can iterate over a Hashtable using its key set, entry set, or legacy Enumeration methods. The entry-set approach is often convenient because it provides each key and value together.

import java.util.Hashtable;
import java.util.Map;

public class HashtableIteration {
    public static void main(String[] args) {
        Hashtable<String, String> capitals = new Hashtable<>();

        capitals.put("India", "New Delhi");
        capitals.put("Japan", "Tokyo");
        capitals.put("France", "Paris");

        for (Map.Entry<String, String> entry : capitals.entrySet()) {
            System.out.println(
                entry.getKey() + " : " + entry.getValue()
            );
        }
    }
}

Possible output:

Japan : Tokyo
France : Paris
India : New Delhi

The order can differ between executions. Do not depend on the iteration order when designing application logic.

10. Understanding Synchronization in Hashtable

The methods of Hashtable are synchronized, so individual operations coordinate access to the table's shared state. This can help prevent simultaneous individual method calls from corrupting the collection's internal structure.

However, synchronization does not automatically make every multi-step operation atomic. For example, checking whether a key exists and then inserting a value are two separate operations. Another thread may change the table between those steps.

Example: A Synchronized Individual Operation

import java.util.Hashtable;

public class HashtableThreadExample {
    public static void main(String[] args) {
        Hashtable<String, Integer> inventory = new Hashtable<>();

        inventory.put("Laptop", 10);
        inventory.put("Phone", 25);

        System.out.println(inventory.get("Laptop"));
    }
}

This example demonstrates ordinary use of the synchronized collection. It does not demonstrate a complete concurrent workflow or guarantee atomicity across multiple method calls.

Important Concurrency Considerations

  • Synchronized methods may add overhead when many threads access the collection.
  • Individual synchronized methods do not make compound operations automatically atomic.
  • For concurrent access with higher scalability, consider ConcurrentHashMap.
  • For compound operations, use appropriate atomic methods such as putIfAbsent() where applicable, or coordinate the entire operation with a suitable locking strategy.
  • Do not assume that synchronizing a collection makes mutable objects stored inside it thread-safe.

11. What Is Properties in Java?

java.util.Properties is a class used to manage configuration settings. It extends Hashtable and is commonly used to store string-based key-value pairs.

Examples of configuration settings include application names, language preferences, service URLs, timeout values, and file paths. Storing such values in a property file allows an application to change configuration without changing its Java source code.

Import Statement

import java.util.Properties;

Common Characteristics

  • Designed primarily for string keys and string values.
  • Provides setProperty() and getProperty() methods.
  • Can load settings from an input stream or a reader.
  • Can save settings to an output stream or a writer.
  • Supports default properties through a defaults object.
  • Inherits synchronization characteristics from Hashtable.

12. Creating and Using a Properties Object

Use setProperty() to add a string property and getProperty() to retrieve it.

import java.util.Properties;

public class PropertiesExample {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.setProperty("app.name", "Student Portal");
        properties.setProperty("app.language", "English");
        properties.setProperty("app.mode", "Development");

        System.out.println(properties.getProperty("app.name"));
        System.out.println(properties.getProperty("app.language"));
        System.out.println(properties.getProperty("app.mode"));
    }
}

Output:

Student Portal
English
Development

Using descriptive property names such as app.name and app.mode helps keep configuration files organized.

13. Important Properties Methods

Method Purpose Example
setProperty(key, value) Adds or updates a string property. p.setProperty("mode", "test");
getProperty(key) Returns the property value or null if not found and no default exists. p.getProperty("mode");
getProperty(key, defaultValue) Returns a value or the supplied fallback. p.getProperty("theme", "Light");
load(InputStream) Loads properties from a byte stream using the properties-file encoding rules. p.load(inputStream);
load(Reader) Loads properties from a character reader. p.load(reader);
store(OutputStream, comments) Writes properties to a byte stream. p.store(outputStream, "Settings");
store(Writer, comments) Writes properties to a character writer. p.store(writer, "Settings");
stringPropertyNames() Returns the names of string properties, including inherited defaults. p.stringPropertyNames();
propertyNames() Returns an enumeration of property names, including defaults. p.propertyNames();
containsKey(key) Checks whether the underlying table contains a key. p.containsKey("mode");
list(PrintStream) Prints a listing of properties for debugging. p.list(System.out);

14. Creating a Properties File

A properties file is a plain-text file that commonly uses the .properties extension. Each entry usually has a key and value separated by an equals sign, a colon, or whitespace.

Create a file named application.properties with the following content:

app.name=Student Portal
app.language=English
app.environment=Development
app.timeout=30
app.notifications=true

Each line represents a configuration setting. Values loaded from the file are strings, so numeric and Boolean values must be converted before they are used as numbers or Boolean values in Java.

15. Loading Properties from a File

The load() method reads properties from a stream or reader. Use try-with-resources to ensure that the file resource is closed properly.

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class LoadProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        try (FileInputStream input =
                 new FileInputStream("application.properties")) {

            properties.load(input);

            String appName = properties.getProperty("app.name");
            String language = properties.getProperty("app.language");
            String environment =
                properties.getProperty("app.environment");

            System.out.println("Application: " + appName);
            System.out.println("Language: " + language);
            System.out.println("Environment: " + environment);

        } catch (IOException e) {
            System.out.println("Could not load configuration: "
                               + e.getMessage());
        }
    }
}

Possible output:

Application: Student Portal
Language: English
Environment: Development

The file path is interpreted relative to the program's working directory when a relative path is used. Ensure the file is located where the application expects it.

16. Loading a Properties File from the Classpath

When a properties file is packaged with an application, it can be placed in the resources directory and loaded from the classpath. This approach is often more portable than relying on a particular working directory.

For example, in a typical Maven project, place the file at src/main/resources/application.properties.

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ClasspathProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        try (InputStream input =
                 ClasspathProperties.class.getClassLoader()
                     .getResourceAsStream("application.properties")) {

            if (input == null) {
                throw new IllegalStateException(
                    "application.properties was not found");
            }

            properties.load(input);

            String appName =
                properties.getProperty("app.name", "Default App");

            System.out.println(appName);

        } catch (IOException e) {
            System.out.println("Error reading properties: "
                               + e.getMessage());
        }
    }
}

If the resource is missing, getResourceAsStream() returns null. Always check for that case before calling load().

17. Retrieving Values with Default Settings

Use getProperty(key, defaultValue) when a setting is optional. This prevents an absent property from unexpectedly producing a null value.

import java.util.Properties;

public class PropertyDefaultsExample {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.setProperty("app.name", "Inventory System");

        String appName =
            properties.getProperty("app.name", "Unknown App");
        String theme =
            properties.getProperty("app.theme", "Light");
        String language =
            properties.getProperty("app.language", "English");

        System.out.println(appName);
        System.out.println(theme);
        System.out.println(language);
    }
}

Output:

Inventory System
Light
English

18. Using Default Properties

A Properties object can be constructed with another Properties object that supplies default values. When a property is not found in the main object, getProperty() can look it up in the defaults object.

import java.util.Properties;

public class DefaultPropertiesExample {
    public static void main(String[] args) {
        Properties defaults = new Properties();
        defaults.setProperty("language", "English");
        defaults.setProperty("theme", "Light");

        Properties userSettings = new Properties(defaults);
        userSettings.setProperty("theme", "Dark");

        System.out.println(userSettings.getProperty("language"));
        System.out.println(userSettings.getProperty("theme"));
    }
}

Output:

English
Dark

The explicitly configured theme value takes precedence over the default. The default language is used because the main object does not define it.

19. Converting Property Values to Other Data Types

Properties are strings. To use a property as an integer, Boolean, or another data type, convert it explicitly and handle invalid input where appropriate.

import java.util.Properties;

public class ConvertProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.setProperty("server.port", "8080");
        properties.setProperty("feature.enabled", "true");

        try {
            int port = Integer.parseInt(
                properties.getProperty("server.port", "8080"));

            boolean enabled = Boolean.parseBoolean(
                properties.getProperty("feature.enabled", "false"));

            System.out.println("Port: " + port);
            System.out.println("Feature enabled: " + enabled);
        } catch (NumberFormatException e) {
            System.out.println("The server port must be a valid integer.");
        }
    }
}

Output:

Port: 8080
Feature enabled: true

Integer.parseInt() throws NumberFormatException when the string is not a valid integer. In contrast, Boolean.parseBoolean() returns true only when the string equals "true", ignoring case; other strings produce false.

20. Saving Properties to a File

The store() method writes property data to a file. It is useful when an application needs to save preferences or updated settings.

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

public class SaveProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.setProperty("username", "student");
        properties.setProperty("theme", "Dark");
        properties.setProperty("notifications", "true");

        try (FileOutputStream output =
                 new FileOutputStream("user-settings.properties")) {

            properties.store(output, "User Settings");
            System.out.println("Settings saved successfully.");

        } catch (IOException e) {
            System.out.println("Could not save settings: "
                               + e.getMessage());
        }
    }
}

Possible output:

Settings saved successfully.

The resulting file includes a comment header and property entries. The order of saved properties is not guaranteed. Do not assume that store() preserves the order in which properties were inserted.

21. Iterating Through Properties

Use stringPropertyNames() to iterate over string property names. This method includes names inherited from a defaults object, which is useful when reading the effective configuration.

import java.util.Properties;
import java.util.Set;

public class IterateProperties {
    public static void main(String[] args) {
        Properties properties = new Properties();

        properties.setProperty("app.name", "Student Portal");
        properties.setProperty("app.mode", "Testing");
        properties.setProperty("app.language", "English");

        Set<String> names = properties.stringPropertyNames();

        for (String name : names) {
            System.out.println(
                name + " = " + properties.getProperty(name));
        }
    }
}

Possible output:

app.mode = Testing
app.name = Student Portal
app.language = English

The iteration order is not guaranteed. If a stable display order is required, sort the property names before printing them.

22. Hashtable vs Properties vs HashMap

Feature Hashtable Properties HashMap
Primary purpose General key-value collection String-based application settings General-purpose key-value collection
Inheritance / interface Implements Map Extends Hashtable Implements Map
Null keys Not allowed Not allowed through its inherited table One null key is allowed
Null values Not allowed Not allowed through its inherited table Null values are allowed
Synchronization Individual methods synchronized Inherits synchronized table operations Not synchronized by default
Property-file support No built-in configuration-file API Provides load() and store() No built-in property-file API
Typical usage Legacy synchronized map code Configuration and preference settings General in-memory maps
Iteration order Not guaranteed Not guaranteed Not guaranteed

23. Hashtable vs ConcurrentHashMap

Although both support concurrent access, they differ in their design and scalability.

  • Hashtable synchronizes its individual methods, generally using the collection instance's monitor.
  • ConcurrentHashMap is designed for concurrent use and generally allows better concurrency between threads.
  • ConcurrentHashMap does not allow null keys or null values.
  • Use ConcurrentHashMap for many modern shared-map scenarios, but choose atomic operations and coordination based on the task's requirements.
  • Use Properties when its configuration-file functionality is needed, not merely because it is synchronized.

24. Common Mistakes and How to Avoid Them

Mistake Why It Is a Problem Correct Approach
Adding a null key to a Hashtable Throws NullPointerException. Validate keys before insertion.
Adding a null value to a Hashtable Throws NullPointerException. Use a non-null value or choose a suitable alternative collection.
Assuming a fixed iteration order Map iteration order is not guaranteed. Sort keys explicitly if order matters.
Expecting Properties to convert types automatically Property values are strings. Convert values and validate the results.
Ignoring a missing configuration file The application may fail to load required settings. Check the resource or path and handle I/O errors.
Using getProperty() without a fallback for optional settings The result can be null. Use getProperty(key, defaultValue) where appropriate.
Storing passwords in a committed properties file Secrets may be exposed in source control or packaged files. Use a secrets manager or protected external configuration.
Assuming synchronization makes multi-step logic atomic Other threads may intervene between operations. Use atomic map operations or suitable synchronization.

25. Best Practices

  • Prefer HashMap for ordinary in-memory key-value storage in single-threaded code when no synchronization is required.
  • Consider ConcurrentHashMap for shared maps accessed by multiple threads.
  • Use Properties for straightforward string-based configuration and preference files.
  • Prefer setProperty() and getProperty() when working with string configuration values.
  • Provide reasonable defaults for optional settings, and validate mandatory settings at startup.
  • Handle IOException and invalid numeric values instead of silently ignoring configuration errors.
  • Keep secrets out of source-controlled configuration files and avoid logging sensitive values.
  • Use try-with-resources for streams and readers.
  • Document property names, expected value formats, and required or optional status.
  • Do not rely on the order of entries in Hashtable or Properties.

26. Practical Exercise

Task: Build a small application configuration manager using Properties.

  1. Create an application.properties file.
  2. Add properties for application name, server port, language, and maintenance mode.
  3. Load the file using a FileInputStream or a classpath resource.
  4. Read the application name and language as strings.
  5. Convert the server port to an integer and handle invalid input.
  6. Read maintenance mode as a Boolean.
  7. Provide default values for optional settings.
  8. Print the effective configuration without exposing secrets.
  9. Update a property and save the settings to a separate file.

Sample Starter Code

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class AppConfig {
    public static void main(String[] args) {
        Properties config = new Properties();

        try (InputStream input =
                 AppConfig.class.getClassLoader()
                     .getResourceAsStream("application.properties")) {

            if (input == null) {
                System.out.println("Configuration file not found.");
                return;
            }

            config.load(input);

            String appName =
                config.getProperty("app.name", "My Application");
            String language =
                config.getProperty("app.language", "English");
            String portText =
                config.getProperty("server.port", "8080");

            int port = Integer.parseInt(portText);

            System.out.println("Application: " + appName);
            System.out.println("Language: " + language);
            System.out.println("Port: " + port);

        } catch (IOException e) {
            System.out.println("Unable to read configuration.");
        } catch (NumberFormatException e) {
            System.out.println("Invalid server port configuration.");
        }
    }
}

Place application.properties in the classpath resources directory and include values such as app.name=Student Portal, app.language=English, and server.port=8080.

27. Interview Questions and Answers

Q1. What is Hashtable in Java?

Answer: Hashtable is a legacy implementation of the Map interface that stores key-value pairs. Its individual methods are synchronized, and it does not allow null keys or values.

Q2. What is the Properties class?

Answer: Properties extends Hashtable and is designed for managing string-based configuration settings. It supports loading and storing data in properties-file format.

Q3. Can Hashtable contain null keys or values?

Answer: No. Inserting a null key or null value causes a NullPointerException.

Q4. What is the difference between put() and setProperty()?

Answer: put() is inherited from Hashtable and accepts objects. setProperty() is intended for string keys and string values. For configuration data, prefer the property-specific method.

Q5. How do you read a value with a fallback?

Answer: Use getProperty("key", "defaultValue"). The default is returned when the property is not found in the object or its defaults.

Q6. How do you load a properties file?

Answer: Create a Properties object, open an input stream or reader, and call load(). Use try-with-resources and handle I/O errors.

Q7. How do you save properties?

Answer: Open an output stream or writer and call store(), supplying a comment if needed.

Q8. Is Hashtable thread-safe?

Answer: Its individual methods are synchronized. However, a sequence of multiple method calls is not automatically atomic, and objects stored inside it are not automatically thread-safe.

Q9. Why might HashMap be preferred over Hashtable?

Answer: HashMap is a modern general-purpose map without built-in synchronization overhead. It permits null keys and values. For concurrent access, consider ConcurrentHashMap instead of choosing Hashtable by default.

Q10. Are values in Properties always strings?

Answer: The intended property API uses strings, but because Properties extends Hashtable, inherited methods can technically insert non-string objects. Such entries may not behave correctly with property-specific methods or storage. Use setProperty() to maintain string-based configuration data.

Q11. Does Properties preserve insertion order?

Answer: No. Do not rely on property iteration or storage order. Sort names explicitly if a stable order is required for display.

Q12. What happens if a property is missing?

Answer: getProperty(key) returns null if the property is absent and no default is available. The overload that accepts a default value can return a fallback instead.


28. Quick Revision Checklist

  • Hashtable stores key-value pairs and implements Map.
  • Hashtable does not allow null keys or null values.
  • Its individual methods are synchronized, but compound operations may need additional coordination.
  • Properties extends Hashtable and is intended for string-based settings.
  • Use setProperty() to assign settings and getProperty() to read them.
  • Use load() to read a properties file and store() to write one.
  • Use a default value for optional configuration entries.
  • Convert strings carefully before using them as numbers or Booleans.
  • Handle missing files, missing settings, and invalid values.
  • Do not depend on the iteration order of either class.
  • Consider HashMap for general storage and ConcurrentHashMap for concurrent map use cases.

29. Conclusion

Hashtable and Properties are useful Java classes to understand when working with key-value data and configuration management. Hashtable provides a synchronized legacy map implementation, while Properties adds convenient methods for reading and writing string-based settings. In modern applications, select a collection based on the actual requirement: use HashMap for ordinary map storage, ConcurrentHashMap for many concurrent-map scenarios, and Properties when the simple properties-file format meets your configuration needs.

To learn more about Java collections, object-oriented programming, and practical Core Java concepts, visit JustAcademy's Core Java Training Course or register for a course demo.

Previous Next
whatsapp