I already know how to initialize Java HashMap by using one of the following 2 ways
// way 1: apply generic type saftey
HashMap<String, Integer> hashMap1 = new HashMap<String, Integer>();
// way 2: general without apply generic type saftey
HashMap<String, Integer> hashMap2 = new HashMap();
My problem
What is the best practice
According to Eclipse Marker
Type safety: The expression of type HashMap needs unchecked conversion
to conform to HashMap
So Its recommend to use
new HashMap<String, Integer>();
But according to Sonar Linter
Replace the type specification in this constructor call with the
diamond operator ("<>").
So Its recommend to use
new HashMap();
Which one is the best? Why?
Use the Java 7 diamond operator:
HashMap<String, Integer> hashMap2 = new HashMap<>();
Diamond <> allows the compiler to infer types implicitly
See: Type Inference for Generic Instance Creation
Related
What is the difference between
Map map = new HashMap<Long, String>();
and
Map map = new HashMap<>();
Which is better for use and why?
The specification HashMap<Long, String>() is simply for the parameter types. But both the use cases you have shown are bad (I would just call it wrong) because the map object has no parameter types. What you should be doing is
Map<Long, String> map = new HashMap<Long, String>();
which is identical to
Map<Long, String> map = new HashMap<>();
The only difference between the two lines is whether you want to rely on automatic type inference of the JDK.
Addendum:
As Boris confirmed, in pre-JDK7, the automatic type inference was not possible, and the second way of initializing the map would not have compiled.
If you are using an IDE (really hope you are), please pay attention to warning about raw use of parametrized types.
Really it should be Map<Long, String> map = new HashMap<>(); The 2 fields in the <> represent the key and value type of the map. So in this example it's a map of Strings which a referenced by Long values. Including them in the declaration forces the Map to ensure that the map can only have specific Key/Value types. It used to be that the types had to be included in the <> of the assignment but it hasn't been needed since Java 7.
I use this common initialization format when I anticipate changing the implementation of the List interface at a later time:
List<Foo> foos = new ArrayList<Foos>();
In an effort to gain the same utility for the values within a Map, I attempted the following but my compiler whines about List<> and ArrayList<> being incompatible types.
Map<String, List<Foo>> fooMap = new HashMap<String, ArrayList<Foo>>;
I've been unable to find an explanation for why I cannot initialize the map in this manner and I'd like to understand the reasoning.
And, sure, this works...
Map<String, List<Foo>> foosMap = new HashMap<String, List<Foo>>;
// ... populate map
ArrayList<Foo> foosAryLst = (ArrayList)foosMap.get("key1");
... but I'm a curious castaphobe. I'd rather fix compile-time errors than runtime errors, things like this aggravate my OCD and the smell of casting conjures an odor similar to the urinal trough after free deep-fried asparagus night at the stadium.
My questions come down to:
Why can I not code my map values to an interface.
Is there a workaround that doesn't require casting?
Any input will be appreciated, thanks!
Sure, there's a workaround that doesn't require casting: don't cast; write
List<Foo> foosLst = foosMap.get("key1");
...and code to the interface with the List as well as the Map.
The root issue, though, is that a Map<String, ArrayList<Foo>> isn't substitutable wherever you'd use Map<String, List<Foo>>. In particular,
Map<String, List<Foo>> map = new HashMap<>();
map.put("foo", new LinkedList<Foo>());
works, but not if map is a Map<String, ArrayList<Foo>>. So one isn't a drop-in substitute for the other.
The declaration that you proposed
Map<String, List<Foos>> fooMap = new HashMap<String, ArrayList<Foos>>();
simply does not make sense: The variable fooMap has the type Map<String, List<Foos>>. This means:
every value that you obtain from this map is a List<Foos>
you may put every value into this list that is (of a subtype of) List<Foos>
If you wanted a map that has ArrayLists as its values, then you would declare it as
Map<String, ArrayList<Foos>> fooMap = new HashMap<String, ArrayList<Foos>>();
If you don't care about the list type, then you can say
Map<String, List<Foos>> fooMap = new HashMap<String, List<Foos>>();
But there's no sensible meaning of mixing the two. Even if you could write what you proposed, then you could still not obtain an ArrayList from this map, because this is simply not the type that fooMap was declared with.
In most cases,
Map<String, List<Foos>> fooMap = new HashMap<String, List<Foos>>();
should be appropriate. Depending on the use case, one could possibly go further by saying
Map<String, List<? extends Foos>> fooMap = new HashMap<String, List<? extends Foos>>();
This way, you can also put lists into the map that contain sublcasses of Foos, like
List<SpecialFoos> specialFoos = ...
fooMap.put("special", specialFoos);
But of course, it's up to you to decide whether this is necessary or not.
The core of the problem is that the compiler cannot keep track of what fooMap may have been assigned to at any particular point in the execution of your code, so there is no way for the compiler to know that
fooMap.put("abc", new ArrayList<Foo>())
should be legal, but that
fooMap.put("abc", new LinkedList<Foo>())
should not be.
All that the compiler knows about the typing of fooMap is its declared type Map<String, List<Foo>>. So, it enforces that whatever object to which you assign fooMap must be able to support all of the operations which a generic Map<String, List<Foo>> is capable of executing. The second line of code above is clearly legal for a Map<String, List<Foo>>, but not legal for a Map<String, ArrayList<Foo>>, so the compiler forbids you from assigning fooMap to a Map<String, ArrayList<Foo>>.
I have a basic question about generics in Java: what is difference between the following two initializations of a map?
Map<String, String> maplet1 = new HashMap<String, String>();
Map<String, String> maplet2 = new HashMap();
I understand the the first initialization is specifying the generics in the object construction, but I don't understand the underlying ramifications of doing this, rather than the latter object construction (maplet2). In practice, I've always seen code use the maplet1 construction, but I don't understand where it would be beneficial to do that over the other.
The second Map is assigned to a raw type and will cause a compiler warning. You can simply use the first version to eliminate the warning.
For more see: What is a raw type and why shouldn't we use it?
The first one is type-safe.
You can shorthand the right side by using the diamond operator <>. This operator infers the type parameters from the left side of the assignment.
Map<String, String> maplet2 = new HashMap<>();
Lets understand the concept of Erasure. At RUNTIME HashMap<String, String>() and HashMap() are the same represented by HashMap.
The process of converting HashMap<String,String> to HashMap (Raw Type) is called Erasure.
Without the use of Generics , you have to cast , say the value in the Map , to String Explicitly every time.
The use of Generics forces you to Eliminate cast.
If you don't use Generics , there will be high probability that a Future Developer might insert another type of Object which will cause ClassCastException
Map<Date, Integer> m = new HashMap<Date, Integer>(); // line 1
Map<Date, Integer> sMap = new TreeMap(m); // line 2
Line 2 gives this error:
Type safety: The expression of type TreeMap needs unchecked conversion
to conform to Map
The solution I found is this: How do I fix "The expression of type List needs unchecked conversion...'?
But, is it safe to simply #SuppressWarnings("unchecked") or is there a scenario when my code will failed. More generally, when can we safely add the #SuppressWarnings("unchecked")?
Try specifying the generic types of the TreeMap when you instantiate it.
Map<Date, Integer> m = new HashMap<Date, Integer>(); // line 1
Map<Date, Integer> sMap = new TreeMap<Date,Integer>(m);
This answer assumes you are using java.util.TreeMap. See: http://docs.oracle.com/javase/7/docs/api/
If you use Java 7, you can use the diamond syntax:
Map<Date, Integer> m = new HashMap<>();
Map<Date, Integer> sMap = new TreeMap<>(m);
The correct way is:
1. Map<Date, Integer> m = new HashMap<Date, Integer>();
2. Map<Date, Integer> sMap = new TreeMap<Date, Integer>(m);
You can also supress the "unchecked" warnings if you are sure about the generic type. In this case, you are.
As already said, adding generic parameters to the TreeMap resolves the problem, as the compiler can now guarantee that no invalid casts will happen. If you omit the generic parameters the compiler cannot give you this guarantee and therefore warns you. Then it is your responsibility that only objects of the correct type are stored in the TreeMap.
If you are you sure that only the correct objects are put into the TreeMap you can safely ignore the warning. If it fails and you encounter class cast exceptions on runtime, it is your own fault (:
Generally speaking if you supress a warning you are effectively ignoring a hint of the compiler that there may be a problem in your code. But the compiler is dumb and there are situations where you can safely say that no problems will occur (e.g. you have other checks in place or a design that does not permit the errors to happen). If that is the case you can suppress the warning.
Eclipse is saying "HashMap is a raw type" When I use the following code
HashMap = new HashMap();
Any idea what could be wrong?
Eclipse will give you that warning when you use a non-Generic HashMap using Java 5 or newer.
See Also: The Generics Lesson in Sun's Java Tutorials.
Edit: Actually, here, I'll give an example too:
Say I want to map someone's name to their Person object:
Map<String, Person> map = new HashMap<String, Person>();
// The map.get method now returns a Person
// The map.put method now requires a String and a Person
These are checked at compile-time; the type information is lost at run-time due to how Java implements Generics.
Nothing wrong exactly, but you are missing out on the wonderful world of generics. Depending on what constraints you want to place on the types used in your map, you should add type parameters. For example:
Map<String, Integer> map = new HashMap<String, Integer>();
That is missing generics, i.e. . If you don't know thise then set the eclipse compiler to java 1.4
Try
HashMap<String,Integer> map = new HashMap<String,Integer>();
instead (obviously replacing the key type (String) and value type (Integer)).
That usually means you're mixing generic code with non-generic code.
But as your example wont even compile its rather hard to tell....
It's missing the generic type. You should specify the key-value generic pair for your map. For instance, the following is a declaration that instantiates a HashMap with String type key and Integer type value.
Map<String, Integer> map = new HashMap<String, Integer>();
All of these are valid answers, you could also use the #SurpressWarnings annotation to get the same result, without having to resort to actual generics. ;)
hashmap is a raw type and hence should be parameterised ie
what ever the data we get through the haspmap function their type must be declared for getting its functions
for example
HashMap<String, Integer> map = new HashMap<String, Integer>();
With the latest Java, you do not have to explicitly mention the variable types in declaration. You can simply put:
= new HashMap<>();