The Answer by Vivin Paliath is correct. I’ll add more information, and more code.
Map#computeIfAbsent
To pair multiple values with one key, use collection as the value type. Often the collection is a List
or Set
. Or perhaps a Map
for more complicated structures.
As an example, suppose we want to track which employees are going to be working on which days of the week.
We define Employee
as a record.
record Employee( int empNum , String name ) { }
Make some sample data.
Employee alice = new Employee( 1 , "Alice" );
Employee bob = new Employee( 2 , "Bob" );
Employee carol = new Employee( 3 , "Carol" );
Each employee maps to a set of day-of-week values. For day-of-week, we can use enum objects defined on java.time.DayOfWeek
. So we need a Map < Employee, Set < DayOfWeek > >
.
Map < Employee, Set < DayOfWeek > > workDaysForEachEmployee = new HashMap <>();
Suppose we want to assign Monday to Alice.
In earlier Java
Here is the old way to make that assignment. We try to retrieve an existing collection value. We do a null-check to see if indeed there was an existing collection value. If so, we add to it, and put it back into map. If not, we instantiate a new collection, add to it, and put it into map.
Set < DayOfWeek > assignedDays = workDaysForEachEmployee.get( alice );
if ( null == assignedDays )
{
assignedDays = EnumSet.noneOf( DayOfWeek.class );
}
assignedDays.add( DayOfWeek.MONDAY );
workDaysForEachEmployee.put( alice , assignedDays );
When run.
workDaysForEachEmployee.toString() = {Employee[empNum=1, name=Alice]=[MONDAY]}
In modern Java 8+
Modern Java brought lambdas, a compact way of passing code as an argument.
We can use lambdas and other new Java 8 functionality to reduce that code seen above to a single line.
We call Map#computeIfAbsent
. In that call we pass a lambda. The lambda creates a collection in which to hold values. If the map already has an entry with our desired collection, the lambda is not executed. One way or another, that computeIfAbsent
method returns a collection value, a Set< DayOfWeek >
in our case.
- If the collection value exists (has already been mapped to a key), the value is returned. In our case, if the employee has already been put into the map with a set of days, that set is retrieved and returned.
- If the collection value does not exist, a new collection is instantiated and returned.
In either case, pre-existing or freshly instantiated, we end up with a set in which to add our DayOfWeek
object for the alice
key.
workDaysForEachEmployee
.computeIfAbsent( alice , ( x -> EnumSet.noneOf( DayOfWeek.class ) ) ) // Returns a `Set< DayOfWeek >`, either a retrieved existing set, or a fresh new set.
.add( DayOfWeek.MONDAY );
workDaysForEachEmployee.toString() = {Employee[empNum=1, name=Alice]=[MONDAY]}
In that code above we instantiate a new collection by calling EnumSet.noneOf( DayOfWeek.class )
. The EnumSet
class is an implementation of Set
that is highly optimized for containing enum objects, using very little memory, and very fast to execute. If you were using another type, such as a List
you might use new ArrayList<>()
.