user3467471
user3467471

Reputation: 147

Object reference in Java differ for various Objects?

would like to know the difference on following methods, namely why two identical (identical by its logic) methods do not return the same expected result:

  1. Method: create a Map of Character and List of Words:

     void setMapping(List<String> words) {
       Map<Character, List<String>> wordsByLetter = new HashMap<>();
       for (String word : words) {
         char letter = word.toLowerCase().charAt(0);
         List<String> ref = wordsByLetter.get(letter);
         if (ref == null) {
           ref = new ArrayList<>();
           wordsByLetter.put(letter, ref);
         }
         ref.add(word);
       }
     }
    

    So in this case we make a reference to List of Strings called 'ref' and it will be updated each time we call method 'add' on it. Unfortunately, the same approach doesn't work with the second one:

2th Method: count all appearances:

void countCategories(List<String> categories) {
  Map<String, Integer> mapper = new HashMap<>();
  for (String category : categories) {
  //need object Integer either to provide reference to it and to check whether it is a null
    Integer counter = mapper.get(category);
    if (counter == null) {
      counter = 0;
      //DOESN'T WORK THE SAME WAY:
      //mapper.put(category, counter);
    }
    counter++;
    mapper.put(category, counter);
  }
}

So, my question is, why the second method doesn't work the same way as the first one, namely, why we cannot update counter in the particular Collection through object reference?

Upvotes: 2

Views: 46

Answers (2)

Eran
Eran

Reputation: 393771

counter is an object of the Integer class, which means it is immutable. Therefore you cannot update its value.

counter++ returns a new Integer instance and assigns it to the counter variable. Therefore, if you call mapper.put(category, counter) before counter++, the original object referenced by counter is stored in the HashMap, and your counter++ statement has no effect on the contents of the HashMap.

That's the reason why the following code doesn't work:

Integer counter = mapper.get(category);
if (counter == null) {
  counter = 0;
  mapper.put(category, counter);
}
counter++;

And instead, you have to write:

Integer counter = mapper.get(category);
if (counter == null) {
  counter = 0;
}
counter++;
mapper.put(category, counter);

The first snippet, where you store ArrayLists in the HashMap is different, since ArrayList is mutable, and calling add for an ArrayList already stored in the HashMap mutates that ArrayList.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

The difference comes from mutability of map's value: List<String> is mutable, while Integer is immutable.

Your second code snippet can be fixed by adding an else as follows:

if (counter == null) {
    mapper.put(category, 1);
} else {
    mapper.put(category, counter+1);
}

or an equivalent conditional expression with no if

mapper.put(category, (counter != null ? counter : 0) + 1);

Upvotes: 1

Related Questions