Converting List to HashMap in Java
Last modified June 1, 2025
This tutorial explores multiple techniques to convert a List
to a
HashMap
in Java, covering traditional for-loops, the modern Stream
API, and advanced scenarios like handling custom objects, duplicate keys, and
grouping elements. These methods are essential for transforming data structures
in Java applications, such as mapping indices to elements or grouping objects by
properties.
Basic Conversion with For-Loop
A straightforward approach to convert a List
to a
HashMap
is using a for-loop, mapping list indices to elements. This
method is simple and suitable for small lists or when explicit control is
needed.
void main() { List<String> fruits = List.of("Apple", "Banana", "Cherry", "Date"); Map<Integer, String> map = new HashMap<>(); for (int i = 0; i < fruits.size(); i++) { map.put(i + 1, fruits.get(i)); // Start indexing from 1 } System.out.println(map); }
This example uses List.of
to create an immutable list of fruits,
then initializes a HashMap
to store index-element pairs. A for-loop
iterates over the list, mapping indices starting from 1 to each fruit, producing
a map where each fruit is associated with a unique index. This approach is
explicit and easy to understand, making it ideal for simple conversions, though
it can become verbose for complex transformations.
Using Stream API
The Stream API provides a functional and concise way to convert a
List
to a HashMap
. Using IntStream
and
Collectors.toMap
, you can achieve the same result as the for-loop
with less code.
void main() { List<String> fruits = List.of("Apple", "Banana", "Cherry", "Date"); Map<Integer, String> map = IntStream.rangeClosed(1, fruits.size()) .boxed() .collect(Collectors.toMap( i -> i, i -> fruits.get(i - 1) )); System.out.println(map); }
In this example, IntStream.rangeClosed(1, fruits.size())
generates
a sequence of indices from 1 to the size of the list, which is then converted to
a Stream<Integer>
using boxed()
to enable use
with Collectors.toMap
.
The toMap
collector maps each index to the corresponding list
element accessed via fruits.get(i - 1)
, producing the same result
as the for-loop example. This method is more concise and aligns with functional
programming principles, offering flexibility for complex mappings, though it may
introduce slight overhead for very small lists due to stream setup.
Converting List of Custom Objects
When working with a List
of custom objects, you can use the Stream
API to map objects to a HashMap
based on a specific field as the
key.
record Product(int id, String name, double price) {} void main() { List<Product> products = List.of( new Product(101, "Laptop", 999.99), new Product(102, "Phone", 699.99), new Product(103, "Tablet", 499.99) ); Map<Integer, Product> map = products.stream() .collect(Collectors.toMap( Product::id, p -> p, (existing, replacement) -> existing // Keep existing entry on duplicate keys )); map.forEach((k, v) -> System.out.printf("ID: %d, Product: %s%n", k, v)); }
This example defines a Product
record with id
,
name
, and price
fields, and creates a list of product
instances. The stream operation uses Collectors.toMap
to map each
product's id
to the product object itself, with a merge function
(existing, replacement) -> existing
to handle potential
duplicate keys by retaining the first occurrence.
The resulting map associates each product's ID with the corresponding product, which is useful for scenarios like mapping database records to their primary keys. The output is formatted to display each key-value pair clearly.
Handling Duplicate Keys
When converting a List
to a HashMap
, duplicate keys
may arise. The Stream API's toMap
collector allows a merge function
to resolve conflicts, such as counting occurrences.
void main() { List<String> fruits = List.of("Apple", "Banana", "Apple", "Cherry", "Apple"); Map<String, Integer> map = fruits.stream() .collect(Collectors.toMap( f -> f, f -> 1, Integer::sum )); System.out.println(map); }
This example processes a list of fruits with duplicates, using
Collectors.toMap
to create a map where each fruit is a key and its
value represents the number of occurrences. Each fruit is initially mapped to a
count of 1, and the merge function Integer::sum
adds the counts for
duplicate keys, resulting in a frequency map (e.g., "Apple" appears three
times).
This approach is ideal for counting occurrences or aggregating data.
Without the merge function, attempting to map duplicate keys would throw an
IllegalStateException
, making the merge function essential for
handling duplicates gracefully.
Grouping List Elements by Property
The Collectors.groupingBy
method groups list elements into a
Map
where the key is a property, and the value is a
List
of matching objects.
record Person(String name, int age, String department) {} void main() { List<Person> people = List.of( new Person("John", 25, "IT"), new Person("Jane", 30, "HR"), new Person("Bob", 25, "IT"), new Person("Alice", 28, "HR") ); Map<String, List<Person>> byDept = people.stream() .collect(Collectors.groupingBy(Person::department)); byDept.forEach((dept, list) -> System.out.printf("%s: %s%n", dept, list.stream() .map(p -> p.name()) .collect(Collectors.joining(", "))) ); }
This example uses Collectors.groupingBy
to group a list of
Person
objects by their department
field, producing a
Map
where each key is a department and the value is a list of
people in that department.
The output is formatted to display only the names of people in each department, joined by commas for readability. This approach is particularly useful for categorizing data, such as grouping employees by department or products by category, making it easier to analyze or display grouped information.
Performance Considerations
Method | Use Case | Performance | Pros | Cons |
---|---|---|---|---|
For-loop | Simple index-based mapping | O(n), minimal overhead | Fast for small lists, explicit control | Verbose, error-prone for complex logic |
Stream API with toMap | Functional transformations | O(n), slight stream overhead | Concise, flexible for complex mappings | Slower for small lists due to stream setup |
Collectors.toMap | Key-value mappings | O(n), efficient for direct mappings | Handles duplicates with merge function | Requires careful key uniqueness handling |
Collectors.groupingBy | Grouping by property | O(n), depends on grouping complexity | Ideal for categorization tasks | More memory for storing grouped lists |
For small lists (<100 elements), for-loops are often faster due to lower overhead.Streams shine in readability and maintainability for complex transformations or parallel processing.
Use LinkedHashMap
instead of HashMap
in
toMap
to preserve insertion order if needed. Avoid null keys/values
in toMap
to prevent
NullPointerException
.
Source
Author
List all Java tutorials.