2

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?

3
  • 1
    Please post a minimal reproducible example Commented Sep 24, 2017 at 10:13
  • I'm not sure what are you trying to ask. Commented Sep 24, 2017 at 10:15
  • 1
    The answer was written in details here stackoverflow.com/q/22793616/3025545 Commented Sep 24, 2017 at 10:21

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I didn't get counter is an object of the Integer class, which means it is immutable. Also, OP has already written the code, which you suggested.
The answer was written in details here stackoverflow.com/q/22793616/3025545
@Ravi The OP asked why he has to write different code in the two snippets (i.e. why mapper.put(category, counter); can't be inside the if statement in the second snippet).
@Eran Ohh.. I didn't get that. :)
1

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);

2 Comments

@Kh.Taheri Although your link explains a closely related concept, it is not an answer to OP's question.
@dasblinkenlight Thank you for your answer, but I believe, Eran had provided much more precise answer providing explicitly, that "counter++ returns a new Integer instance and assigns it to the counter variable", cause otherwise I would provide an example that doubt the immutability of the object Integer as follows: Integer counter = null; if (counter == null) { counter = 0; } counter++; System.out.println(counter); //result = 1;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.