I'm using a recursive tree of hashmaps, specifically Hashmap map where Object is a reference to another Hashmap and so on. This will be passed around a recursive algorithm:
foo(String filename, Hashmap<String, Object> map)
{
//some stuff here
for (Entry<String, Object> entry : map.entrySet())
{
//type warning that must be suppressed
foo(entry.getKey(), (HashMap<String, Object>)entry.getValue());
}
}
I know for sure Object
is of type Hashmap<String, Object>
but am irritated that I have to suppress the warning using @SuppressWarnings("unchecked")
.
I'll be satisfied with a solution that does either a assert(/*entry.getValue() is of type HashMap<String, Object>*/)
or throws an exception when it isn't. I went down the Generics route for compile type safety and if I suppress the warning then it defeats the purpose.
Thank you for your comments, ksb
Generics were added to Java to ensure type safety. And to ensure that generics won't cause overhead at runtime, the compiler applies a process called type erasure on generics at compile time. Type erasure removes all type parameters and replaces them with their bounds or with Object if the type parameter is unbounded.
We can use generics while defining our builders to tell Java that return type of methods is not the builder's class but rather the subclass of the builder, hence recursive generic definition.
Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.
Java generics are implemented through type erasure, i.e. type arguments are only used for compilation and linking, but erased for execution. That is, there is no 1:1 correspondence between compile time types and runtime types.
This is possible using a generic method with a recursive type variable. Try the following:
public <T extends Map<String, T>> void foo(String filename, T map) {
//some stuff here
for (Map.Entry<String, T> entry : map.entrySet()) {
foo(entry.getKey(), entry.getValue());
}
}
Should compile fine without any warnings.
However, if you have control of the map, and can substitute your own class, it might be more readable to make a class Node (this looks like a tree to me), that contains a Map instead. Something like:
public class Node {
private Map<String, Node> children;
...
// accessor methods to retrieve children ...
}
And have foo
take a Node
as its second argument instead. Just a suggestion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With