Amir Rachum
Amir Rachum

Reputation: 79615

Map generics in Java

I seem to have a bit of misunderstanding with Java Generics and I hope you can help me. I tried to create a map like so:

Map<Debater, int>

(Debater is an Interface I declared) but java complained about the int, so I did:

Map<Debater, Integer>

I suppose it's because int is not a class while Integer is, is this correct?

Also, Now I get a Debater and I need to add 1 to its value in the map. How do I do that?

Upvotes: 2

Views: 723

Answers (7)

polygenelubricants
polygenelubricants

Reputation: 383726

Java does not allow primitive types in generics. Fortunately, each of the primitive types has a "box" reference type, e.g. Integer for int, Boolean for boolean, etc. The language is aware of this association, and can do automatic boxing and unboxing for you. This means that you can do something like this:

 Integer i = 5;
 i++;

There are some caveats with automatic boxing/unboxing that you have to be aware of. The classic example is the following:

 List<Integer> list = new ArrayList<Integer>();
 list.add(3);              // this is autoboxed, and calls list.add(E)
 list.remove(3);           // this invokes list.remove(int) overload !!!!
 list.remove((Integer) 3)  // this is how you call list.remove(E)

You will find that the above code as is will throw IndexOutOfBoundsException, because the first remove tries to remove the 3rd element, instead of the element 3.

Upvotes: 2

Bozho
Bozho

Reputation: 597046

Yes, you are correct.

As for incrementing:

map.put(debater, map.get(debater) + 1);

Autoboxing will take care of "switching" between the object and the primitive.

Note that this (as noted in the comments) will throw a NullPointerException if you don't have a value for this debater in the map already. So if you want to do 2-in-1, it can be reworked as follows:

map.put(debater, map.containsKey(debater) ? map.get(debater) + 1 : 1);

Upvotes: 7

Thomas L&#246;tzer
Thomas L&#246;tzer

Reputation: 25381

You are correct about the int vs. Integer part.

To increment the value safely use:

Integer currentValue = map.get(debater);
if(currentvalue == null) {
    map.put(debater, 1);
} else {
    map.put(debater, currentValue  + 1);
}

or you could use map.contains(debater) first if you want to handle the case that a debater is not contained in the map separately.

Upvotes: 2

Valentin Rocher
Valentin Rocher

Reputation: 11669

You're right, it's because you have to specify a class.

As for your question, you juste have to do :

myMap.put(myDebater, myMap.get(myDebater) + 1);

All conversions between int and Integer will be done by autoboxing.

Upvotes: 2

BalusC
BalusC

Reputation: 1108662

That's correct. A Map can only hold Objects.

Also, Now I get a Debater and I need to add 1 to it's its value in the map. How do I do that?

I suggest you to grab AtomicInteger for that so that it's more failsafe in case of multithreaded environments.

Map<Debater, AtomicInteger> map = new HashMap<Debater, AtomicInteger>();
// ...

map.get(debater).incrementAndGet();

Else you'll need to add more code to synchronize the update to avoid that threads get the "wrong" value.

Upvotes: 4

Michael Borgwardt
Michael Borgwardt

Reputation: 346260

I suppose it's because int is not a class while Integer is, is this correct?

Correct.

Also, Now I get a Debater and I need to add 1 to it's value in the map. How do I do that?

This should do the trick:

map.put(debater, map.get(debater)+1);

Upvotes: 3

Crozin
Crozin

Reputation: 44376

You cannot use primitive type (such as int, float, char etc.) as a generic type - collections in Java are generic. That's why you have to use Integer instead of int.

Upvotes: 1

Related Questions