The newSetFromMap() method in Java is a utility method provided by the java.util.Collections class. It is used to create a Set that is backed by a specified Map. This method is useful when you want to use a map to implement the set interface, allowing you to leverage the capabilities of maps while maintaining the uniqueness properties of a set.
Table of Contents
- Introduction
newSetFromMap()Method Syntax- Examples
- Basic Usage of
newSetFromMap() - Using
newSetFromMap()with Custom Classes
- Basic Usage of
- Real-World Use Case
- Conclusion
Introduction
The Collections.newSetFromMap() method returns a Set backed by a specified map. This method allows you to create a set where the elements are stored as keys in the map, with the associated value being a dummy Boolean value (typically Boolean.TRUE). Any changes to the set are reflected in the map and vice versa.
This method is particularly useful when you need to maintain additional information about the set elements or when you require a set implementation with specific characteristics provided by a particular map implementation (e.g., ConcurrentHashMap for concurrency).
newSetFromMap() Method Syntax
The syntax for the newSetFromMap() method is as follows:
public static <E> Set<E> newSetFromMap(Map<E, Boolean> map)
Parameters:
map: The map to be used for backing the set. The map must be empty when this method is called.
Returns:
- A set backed by the specified map.
Throws:
IllegalArgumentExceptionif the specified map is not empty.
Examples
Basic Usage of newSetFromMap()
The following example demonstrates how to use the newSetFromMap() method to create a set backed by a HashMap.
Example
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class NewSetFromMapExample {
public static void main(String[] args) {
// Create an empty HashMap
Map<String, Boolean> map = new HashMap<>();
// Create a set backed by the HashMap
Set<String> set = Collections.newSetFromMap(map);
// Add elements to the set
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// Display the set
System.out.println("Set: " + set);
// Display the underlying map
System.out.println("Underlying Map: " + map);
// Attempt to add a duplicate element
set.add("Apple");
// Display the set and map after attempting to add a duplicate
System.out.println("Set after adding a duplicate: " + set);
System.out.println("Underlying Map after adding a duplicate: " + map);
}
}
Output:
Set: [Apple, Cherry, Banana]
Underlying Map: {Apple=true, Cherry=true, Banana=true}
Set after adding a duplicate: [Apple, Cherry, Banana]
Underlying Map after adding a duplicate: {Apple=true, Cherry=true, Banana=true}
Using newSetFromMap() with Custom Classes
You can also use the newSetFromMap() method with sets containing instances of custom classes.
Example
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
class Student {
String name;
Student(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Student student = (Student) obj;
return name.equals(student.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return name;
}
}
public class CustomSetExample {
public static void main(String[] args) {
// Create an empty HashMap for Student objects
Map<Student, Boolean> map = new HashMap<>();
// Create a set backed by the HashMap
Set<Student> studentSet = Collections.newSetFromMap(map);
// Add students to the set
studentSet.add(new Student("Amit"));
studentSet.add(new Student("Neha"));
studentSet.add(new Student("Raj"));
// Display the set of students
System.out.println("Student Set: " + studentSet);
// Display the underlying map
System.out.println("Underlying Map: " + map);
// Add a duplicate student
studentSet.add(new Student("Amit"));
// Display the student set and map after adding a duplicate
System.out.println("Student Set after adding a duplicate: " + studentSet);
System.out.println("Underlying Map after adding a duplicate: " + map);
}
}
Output:
Student Set: [Neha, Amit, Raj]
Underlying Map: {Neha=true, Amit=true, Raj=true}
Student Set after adding a duplicate: [Neha, Amit, Raj]
Underlying Map after adding a duplicate: {Neha=true, Amit=true, Raj=true}
Explanation:
-
Backed Set: The
newSetFromMap()method creates a set that is backed by the specified map, meaning any changes to the set are reflected in the map. -
Immutable Nature: The set’s elements are stored as keys in the map with
Boolean.TRUEas the value. This approach ensures that the set only contains unique elements. -
Custom Class: In the custom class example,
Studentobjects are stored in the set, demonstrating how custom elements can be added.
Real-World Use Case
Leveraging Concurrent Maps for Thread-Safe Sets
In real-world applications, the newSetFromMap() method can be used to create thread-safe sets backed by concurrent maps, allowing for safe concurrent access in multithreaded environments.
Example
Imagine a scenario where you need a thread-safe set of unique tasks in a concurrent application.
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
class Task {
String description;
Task(String description) {
this.description = description;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Task task = (Task) obj;
return description.equals(task.description);
}
@Override
public int hashCode() {
return description.hashCode();
}
@Override
public String toString() {
return description;
}
}
public class ConcurrentTaskManagerExample {
public static void main(String[] args) {
// Create a ConcurrentHashMap for thread-safe operations
Map<Task, Boolean> taskMap = new ConcurrentHashMap<>();
// Create a thread-safe set backed by the ConcurrentHashMap
Set<Task> taskSet = Collections.newSetFromMap(taskMap);
// Add tasks to the thread-safe set
taskSet.add(new Task("Review code"));
taskSet.add(new Task("Write tests"));
taskSet.add(new Task("Deploy application"));
// Display the task set
System.out.println("Task Set: " + taskSet);
// Display the underlying map
System.out.println("Underlying Map: " + taskMap);
// Add a duplicate task
taskSet.add(new Task("Review code"));
// Display the task set and map after adding a duplicate
System.out.println("Task Set after adding a duplicate: " + taskSet);
System.out.println("Underlying Map after adding a duplicate: " + taskMap);
}
}
Output:
Task Set: [Deploy application, Write tests, Review code]
Underlying Map: {Deploy application=true, Write tests=true, Review code=true}
Task Set after adding a duplicate: [Deploy application, Write tests, Review code]
Underlying Map after adding a duplicate: {Deploy application=true, Write tests=true, Review code=true}
Explanation:
-
Thread Safety: By using a
ConcurrentHashMapas the backing map, the set becomes thread-safe, allowing for safe concurrent operations. -
Unique Elements: The set ensures that only unique tasks are stored, with no duplicates allowed.
Conclusion
The Collections.newSetFromMap() method is a powerful utility for creating a set backed by a specified map in Java. By providing a way to leverage map implementations for set storage, it enhances the flexibility and capabilities of your code. This method is particularly valuable in scenarios where you need to maintain unique elements with specific characteristics provided by different map implementations, improving the robustness and maintainability of your Java applications.