Is it a bad practice to instantiate private variable in a class to avoid the NullPointerException when using the variable, for example:
public Class MyClass{
private HashMap<String, String> myHashMap = new HashMap<String, String>();
public HashMap<String, String> getMyHashMap (){return myHashMap; }
public HashMap<String, String> setMyHashMap (String myString){ /* treatment to set the myHashMap under some conditions */}
}
If we don't instantiate the myHashMap, the method getMyHashMap() may return null
Is it a better practice that the caller of getMyHashMap() checks for the null value?
Is there a coding good practice to be applied in those circumstances?
I use two solutions for this kind of situations. If myHashMap has to be always available, set it as final and initialize with value:
private final HashMap<String, String> myHashMap = new HashMap<String, String>();
public HashMap<String, String> getMyHashMap () {
return myHashMap;
}
If myHashMap is something bigger than empty object I rather preffer to do something like a lazy loading:
private HashMap<String, String> myHashMap;
public HashMap<String, String> getMyHashMap () {
if (myHashMap == null) {
myHashMap = new HashMap<String, String>();
}
return myHashMap;
}
It is perfectly ok.
A common pattern in programming is iterating over a collection or map that is returned from a method. If the method possibly returns null, the onus is on the caller to perform a null check before attempting to iterate over the collection or map. Thus, it is normally considered bad practice to return null from public methods that return a collection or map. A better alternative would be to return an empty collection or map, as these allow safe iteration without a NullPointerException.
While not recommended, it is ok to return null from a private method that returns a collection or map, since their scope is limited to the enclosing class.
No. It is not a bad practice.
By doing this, you are establishing up an invariant for the class: myHashMap is not null. This invariant makes reasoning about the correct functioning of the rest of the class easier: you know that myHashMap is not null, so you won't get NullPointerException when you try to access it.
You can implement this by assigning the value in an initializer block (which your code is equivalent to) or assigning the value in the constructor. The two are roughly equivalent; actually, assigning the field when you declare it becomes an initializer block, which is executed before the constructor.
You can strengthen your reliance upon this invariant by making myHashMap final: this means that you can't accidentally set it to null later.
You don't strictly need this invariant: as #hsz suggests, you can make the value non-null lazily. However, I would argue that this clutters the class, and makes it harder to reason about. It's also harder to change the class to add new functionality: you have to remember to add that lazy instantiation to new code if it requires access to myHashMap.
I would say it is much better to create it once-and-for-all when you create the instance, and get on with the rest of your code - especially for something as trivial as an empty HashMap.
You could instantiate your map in the constructor.
public Class MyClass{
private HashMap<String, String> myHashMap;
public MyClass(){
myHashMap = new HashMap<String, String>();
}
public HashMap<String, String> getMyHashMap (){ return myHashMap; }
public HashMap<String, String> setMyHashMap (String myString){ /* treatment to set the myHashMap under some conditions */}
}
This way, getMyHashMap will never return null
Related
I got a scenario like the following:
Map1 - Map<String, Map<String,List<Vo>>>
Map2 - Map<String, Set<String>
Is it possible to set the same have a same key reference for the above 2 Maps like the following?
Map<String, Collection<?> mapCommon=new HashMap<String, Collection<?>();
Can anyone please give some idea about how to set this?
edit: yes same reference
You are touching here two interesting elements.
Firstly - Map does not belong to Collection. List and Set do belong, but Map is a different one even though it shares some commonalities with Lists and Sets.
Secondly - Mixing the types into one commonMap the way you are trying is doable but it should be avoided as it is generally not considered as best practice. The problem we are dealing with is caused by type erasure. Once compiler compiles the code - it does not pass any information about generic types hold by Map or Set. Effectively your Map<String, List<Vo>> becomes raw-type Map<?> in the compiled code. The problem with that is casting back original values. The compiler will not allow you to check the instance if it is Map<String, List<Vo>> or Set<String>.
The fllowing piece of code will fail:
public static void processElement(Object commonMapObjectEitherMapOrSet) {
if (commonMapObjectEitherMapOrSet instanceof Map<String, List<Vo>>) {
//...
}
}
Error: Cannot perform instanceof check against parameterized type
Map>. Use the form Map instead since further
generic type information will be erased at runtime
The possible workaround would be to forget about generics and check if the instance is a raw-type Set or Map. The code below shows how check if Object is either Map or Set.
public static void processElement(Object commonMapObjectEitherMapOrSet) {
if (commonMapObjectEitherMapOrSet instanceof Map) {
System.out.println("Got map; but types held in the map are not known due to type-erasure");
// This is where things will get messy as you will get warnings:
Map<String, List<Vo>> map = (Map<String, List<Vo>>) commonMapObjectEitherMapOrSet;
// ...
}
if (commonMapObjectEitherMapOrSet instanceof Set) {
System.out.println("Got set; but types held in the set are not known due to type-erasure");
// This is where things will get messy as you will get warnings:
Set<String> set = (Set<String>) commonMapObjectEitherMapOrSet;
// ...
}
}
The problem with the above is casting the value from your commonMap back to your desired types ie. Map<String, List<Vo>> and Set<String>. The compiler won't be able to check if the casting is correct and will issue a warning. You can technically Suppress the warning with (#SuppressWarnings("unchecked") annotation ) but this may not be the best thing to do.
At this stage - it makes sense to consider whether or not to create your own specialized class to manage different types.
Back to your original question - to answer it I am posting the code that maps things to the common map:
package stackoverflow;
import java.util.*;
class Vo {}
public class MultipleRefs {
public static void main(String[] args) {
Map<String, List<Vo>> mapVo = new HashMap<>();
Set<String> set = new HashSet<>();
Map<String, Object> commonMap = new HashMap<>();
//commonMap.put("a", Map)
commonMap.put("mapVoOne", mapVo);
commonMap.put("setOne", set);
commonMap.forEach((key, value) -> processElement(value));
}
public static void processElement(Object commonMapObject) {
if (commonMapObject instanceof Map) {
System.out.println("Got map; but types held in the map are not known due to type-erasure");
// This is where things will get messy:
Map<String, List<Vo>> map = (Map<String, List<Vo>>) commonMapObject;
System.out.println(" processElement prints map: " + map);
}
if (commonMapObject instanceof Set) {
System.out.println("Got set; but types held in the set are not known due to type-erasure");
// This is where things will get messy:
Set<String> set = (Set<String>) commonMapObject;
System.out.println(" processElement prints set: " + set);
}
}
}
If I understand you would want to have the same key to be used for various different types of values.
Why not have a new Class itself that would consists of maps, sets, whose instances could be used as values
class MyClass {
private Map<String, List<Vo>> theMap;
private Set<String> theSet;
...
... // have its own getters and setters
}
And then you can have your top level map defined like this
Map<String, MyClass> myMainMap = new HashMap<String, MyClass>();
Or as an alternative have a tuple
You can check this link further to see how that is done.
What you want to do is impossible because Set and Map do not share any common implementation or super class except Object. You can see it in the official documentation :
Javadoc Map
Javadoc Set
You could do a Map<String, Object> but I strongly not advise you to doing that. How could you know if your object is a map or a set ? It is not possible to do that properly.
In my opinion, the best solution you have is to create a new class to wrap your two collections :
public class YourWrapper {
Map<String, Map<String,List<Vo>>> a;
Map<String, Set<String> b;
// getter setter etc...
}
After that you can create your collection :
Map<String, YourWrapper> myMap = new HashMap<String, YourWrapper>();
I have a method that maps keywords to a certain value. I want to return the actual hashmap so I can reference its key/value pairs
Yes. It is easily possible, just like returning any other object:
public Map<String, String> mapTheThings(String keyWord, String certainValue)
{
Map<String, String> theThings = new HashMap<>();
//do things to get the Map built
theThings.put(keyWord, certainValue); //or something similar
return theThings;
}
Elsewhere,
Map<String, String> actualHashMap = mapTheThings("keyWord", "certainValue");
String value = actualHashMap.get("keyWord"); //The map has this entry in it that you 'put' into it inside of the other method.
Note, you should prefer to make the return type Map instead of HashMap, as I did above, because it's considered a best practice to always program to an interface rather than a concrete class. Who's to say that in the future you aren't going to want a TreeMap or something else entirely?
i´m trying to make a casting of Hasmap
I have this hasmap:
Map<String, Object> requestargs = new Map<String, Object>();
Other side i have a method who bring me a hashmap of: Map<String, Document>
MultipartForm form = MgnlContext.getWebContext().getPostedForm();
The method is getDocuments();
I need to put the return of this method in my hashmap making something like this:
requestargs = form.getDocuments();
But i don´t know how to cast this Hasmap og (String,Document) to (String,Object)
Thanks
Unless you can use a wildcard
Map<String, ? extends Object> requestargs
You will need to copy the map into a new map:
requestargs = new HashMap<String, Object>(form.getDocuments());
The two types are not related directly. Were you able to make the assignment directly (or via casting) it would be possible to insert a value with non-Document type into the map, and that would be type-unsafe:
Map<String, Document> docs = form.getDocuments();
Map<String, Object> requestargs = docs; // not actually allowed
requestargs.put("Foo", new Object());
for (Document doc : docs.values()) {
// doc isn't necessarily a Document! ClassCastExceptions abound.
}
To prevent this problem happening, such an assignment is forbidden by the type system.
The wildcard works because it makes it impossible to call put on the map, since there is no way to know what types can be put into the map safely.
I have Two Maps
Map<String, String> filterMap
Map<String, Object> filterMapObj
What I need is I would like to convert that Map<String, String> to Map<String, Object>.
Here I am using the code
if (filterMap != null) {
for (Entry<String, String> entry : filterMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
Object objectVal = (Object)value;
filterMapObj.put(key, objectVal);
}
}
It works fine, Is there any other ways by which I can do this without iterating through all the entries in the Map.
Instead of writing your own loop that calls put, you can putAll, which does the same thing:
filterMapObj.putAll(filterMap);
(See the Javadoc.)
And as Asanka Siriwardena points out in his/her answer, if your plan is to populate filterMapObj immediately after creating it, then you can use the constructor that does that automatically:
filterMapObj = new HashMap<>(filterMap);
But to be clear, the above are more-or-less equivalent to iterating over the map's elements: it will make your code cleaner, but if your reason for not wanting to iterate over the elements is actually a performance concern (e.g., if your map is enormous), then it's not likely to help you. Another possibility is to write:
filterMapObj = Collections.<String, Object>unmodifiableMap(filterMap);
which creates an unmodifiable "view" of filterMap. That's more restrictive, of course, in that it won't let you modify filterMapObj and filterMap independently. (filterMapObj can't be modified, and any modifications to filterMap will affect filterMapObj as well.)
You can use the wildcard operator for this.
Define filterMapObj as Map<String, ? extends Object> filterMapObj and you can directly assign the filterMap to it. You can learn about generics wildcard operator
You can simply write
Map<String, Object> filterMapObj = new HashMap<>(filterMap);
You can use putAll method to solve the problem.The Object is the father class of all objects,so you can use putAll without convert.
I am wondering if there's an elegant solution for doing this in Java (besides the obvious one - of declaring a different/explicit function. Here is the code:
private static HashMap<String, Integer> nameStringIndexMap
= new HashMap<String, Integer>();
private static HashMap<Buffer, Integer> nameBufferIndexMap
= new HashMap<Buffer, Integer>();
// and a function
private static String newName(Object object,
HashMap<Object, Integer> nameIndexMap){
....
}
The problem is that I cannot pass nameStringIndexMap or nameBufferIndexMap parameters to the function. I don't have an idea about a more elegant solution beside doing another function which explicitly wants a HashMap<String, Integer> or HashMap<Buffer, Integer> parameter.
My question is:
Can this be made in a more elegant solution/using generics or something similar?
Thank you,
Iulian
You could make your function generic too:
private static <E extends Object> String newName(E object,
HashMap<E, Integer> nameIndexMap){
....
}
This bounds the two parameters of the function together, so for a HashMap<String, Integer> you can only pass String instances as first parameter. This may or may not be what you exactly want: if you only want to get elements from the map, Jon's solution is simpler, but if you want to add this object to the map, this one is the only choice.
You want something like this:
private static String newName(Object object,
HashMap<? extends Object, Integer> nameIndexMap) {
....
}
or (as pointed out in the comments)
private static String newName(Object object,
HashMap<?, Integer> nameIndexMap) {
....
}
That will stop you from putting anything into the map, because you couldn't guarantee to get the key right - but you can get things out of the map and guarantee they'll be integers.
Note that this version doesn't make the method generic - which means it's simpler, but it doesn't provide the same type safety that Peter's version does, in that you can't guarantee that object is of the right type. Each approach has its pros and cons - use whatever is most appropriate based on the body of the method. (If you need to put an entry into the map, Peter's approach is definitely better.)