not generic Error in Java HashMap - java

I am getting the below error for HashMap in the Java code.
Error - "The type HashMap is not generic; it cannot be parameterized with arguments <>"
package com.example.map;
import java.util.Map;
import java.util.HashMap;
public class HashMap {
public static void main(String[] args) {
// compilation error here vvvvvvv
Map<Integer, String> mapHttpErrors = new HashMap<>();
mapHttpErrors.put(200, "OK");
mapHttpErrors.put(303, "See Other");
mapHttpErrors.put(404, "Not Found");
mapHttpErrors.put(500, "Internal Server Error");
System.out.println(mapHttpErrors);
}
}

You have named your own class HashMap as well.
When you write new HashMap the compiler thinks you're referring to your own class which indeed does not specify any generic parameters.
You can (and in fact: should) either change the name of your class to something else or explicitly refer to java.util.HashMap in your code:
Map<Integer, String> mapHttpErrors = new java.util.HashMap<>();

As the error is telling you, your HashMap class isn't generic, so your code makes no sense.
You should not make classes with the same names as built-in classes.

In the following line HashMap refers to the public class you created:
Map<Integer, String> mapHttpErrors = new **HashMap**<>();
Naming your class with exact the same name as classes from official Java API is often a very bad idea. But if you're sure that instead of that, you still want to keep the old name, here is the way you can use the HashMap from java.util package:
Map<Integer, String> mapHttpErrors = new java.util.HashMap<>();
But again, remember that naming your classes as you did in your program is rather a bad idea.

Related

Hashmap to Function<string, string> to Hashmap?

Currently have code that initializes a Function<String, Object> lookup variable:
Map<String, String> map = new HashMap<>();
...
lookup = map::get;
Is it possible to derive the HashMap from this lookup variable? According to (https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html) there may not be. Possibly a domain getter and an output getter for Function<String, Object> types?
This might or might not feasible: when Java generate the lambda, it creates an implementation of Function which reference variables used by the lambda as synthetic fields. Since the lambda is map::get, there is a synthetic field for the map.
Using this code and jdoodle, or any java 11 compiler:
import java.util.*;
import java.util.function.*;
import java.lang.reflect.*;
public class MyClass {
public static void main(String args[]) {
Map<String, String> map = new HashMap<>();
Function<String, String> lookup = map::get;
System.out.println(lookup);
System.out.println(lookup.getClass());
for (Field field : lookup.getClass().getDeclaredFields()) {
System.out.println(field);
}
}
}
If you execute the code, you should see a field:
MyClass$$Lambda$1/0x0000000100060c40#4c3e4790
class MyClass$$Lambda$1/0x0000000100060c40
private final java.util.Map MyClass$$Lambda$1/0x0000000100060c40.arg$1
The MyClass$$Lambda$1/0x0000000100060c40.arg$1 is the reference to map.
As you can see, the name is generated and not very easy to predict: you could certainly assume "somewhere" that if there is one field of type Map, then it may be the map used in map::get.
The field is private and with Java 11, you don't know the module of the generated class: you may not even access it using reflection (or java.lang.invoke.MethodHandle).
The short answer is no, it is not reasonably possible. Neither I think you should try to do it unless you want to know how it works.

Unable to create a class with name Entry

Following code fails compilation with error following error message :
Type mismatch: cannot convert from element type Test1.Entry to
Map.Entry
My question is can't we ever use class with name Entry in our project while using hash map ? And why this error is there though i did not import any Entry class here.
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class Test1 {
public static class Entry<T> {
public String m() {
return "A";
}
}
public static void main(String[] args) {
final Set<Entry> a = new HashSet<>();
new HashMap<String, Entry>() {
{
for (final Entry entry : a) {
put(entry.m(), entry);
}
}
};
}
}
Is there any way I can keep this class name and code compiles successfully.
Since you are using double brace initialization the maps internals are exposed in that block.
Either rename the Entry class or move the initialization code out of the init block of the HashMap so your Entry does not shadow the maps internal Entry implementation.
final HashMap<String, Entry> map = new HashMap<>();
for (final Entry entry : a) {
map.put(entry.m(), entry);
}
You have a issue with the names:
your Entry<T> is shadowing at some point the java.util.Map.Entry<K, V>
just rename the Entry to something else
public static class MyEntry<T> {
public String m() {
return "A";
}
}
You need to tell the compiler that you want to use Entry interface provided by java.util.
As you already have a class named Entry in the same package in which you are using it hence it is implicitly imported. For all the places where you intent to use Entry from java.util you have to explicitly use java.util.Map.Entry instead of just Entry. This way you can use both the classes.
This snapshot might clear your doubt,
As error popup states, the compiler is thinking that Inside your for loop it's java.util.Map.Entry but you want to traverse over your custom Entry class over here.
Even though you assume that you aren't importing java.util.Map.Entry, Try removing 1st import (i.e. HashMap) and you will see that you are no longer getting Incompatible Types Error.
You can try any of the suggested workarounds to get rid of this problem.

Android enum reflection

I have been trying for the past few hours to get the following functionality working.
public class OMG {
String name;
HashMap<SETTINGS, String> settings;
public enum SETTINGS {
Setting1("OMG setting 1"), Setting2("OMG setting 2");
private String key;
#Override
public String toString() {
return "SETTINGS: " + key;
}
SETTINGS(String key){
this.key = key;
}
}
public OMG(String name, HashMap<SETTINGS, String> settings) {
this.name = name;
this.settings = settings;
}
}
and
public class Test {
public static void main(String[] args) {
try {
Class<?> c = Class.forName("path.to.OMG" + "$" + "SETTINGS");
System.out.println(Arrays.toString(c.getEnumConstants()));
HashMap<c,String > values = new HashMap<>();
OMG omg = new OMG("blah",values);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
I have to create an OMG instance and am been given the path to OMG and the enum NAME. So far I have the code in the Test class. I am able to get all enumValues however I have no idea how to create a HashMap and how to call the constructor with this HashMap to get an instance of the OMG class.
Please help.
Thank you
There is no practical reason for doing what you are trying to do. The way to instantiate an OMG is to do new OMG("foo", new HashMap<SETTINGS, String>());
However, as a purely academic exercise (I like these!), let's see if we can instantiate an OMG only using class names given as strings and without actually typing OMG or SETTINGS anywhere. It can be done!
In Java, generics are a compile-time feature only. At runtime, a HashMap<SETTINGS, String> is no different from a HashMap<Double, Float> or a raw HashMap. Therefore you can instantiate any old HashMap - there is no need to use the object c at all (and you can't use a Class object as a type parameter liken this anyway).
Here is a solution:
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("path.to.OMG");
Constructor constructor = clazz.getConstructor(String.class, HashMap.class);
Object omgInstance = constructor.newInstance("foo", new HashMap<Void, Void>());
System.out.println(omgInstance.getClass()); // OMG - it worked!
}
From your own answer, I read that you want to use enum entries as keys and default values for the actual configuration that is stored in the map in the class OMG. This configuration should also be written to a file.
Now, you have to make a design decision: When do you want to be able to change which configuration keys can be used and/or the default values? While the program is already running (at run-time) or when the program is recompiled (at compile-time)?
Your description suggests that you want to be able to change them at run-time. Is this correct? Also, is this really needed? Your existing code will probably not use values which are provided for the new keys. Also, a changed default value will probably not have an effect, since the value was already initialized using the old default value.
If you really want to change these information at run-time, then you should not use an enum to store and load them. While this style of programming might work in scripting languages like JavaScript, it does not work well in Java. An enum, like any other code is not supposed to be changed at run-time, but it should be given at compile-time.
Since in Java the code is not supposed to be changed at run-time, the JVM does not even allow to simply reload a class, without doing some class loader magic. You normally want to avoid this whenever possible. For more information about this, see here. It is not impossible to reload a class at run-time, but it is definitely the wrong solution to the problem that you are facing.
So, what is a correct solution? I am still not convinced that you really need to change the information at run-time. If this is correct and you only need to change the information at compile-time, you can simply use your current enum approach. However, you can simplify it to not load the class by name, please see below for more details about a possible implementation.
If you really need to be able to change the information at run-time, you should not store the information in the code, but in a file. This enables you to easily reload the information by re-reading the file. You can use a properties file, which is common in the Java world, see here. If you need a more structured file format, you can use a JSON file. In Java, you can use Gson to work with JSON files, see here.
This works for me:
package test;
import java.util.Arrays;
import java.util.EnumMap;
public class Test {
public static enum SETTINGS {
Setting1("OMG setting 1"), Setting2("OMG setting 2");
private String key;
#Override
public String toString() {
return "SETTINGS: " + key;
}
SETTINGS(String key) {
this.key = key;
}
}
public static class OMG<E extends Enum<E>> {
String name;
EnumMap<E, String> settings;
public OMG(String name, EnumMap<E, String> settings) {
this.name = name;
this.settings = settings;
}
public static <E extends Enum<E>> OMG<E> create(String name,
Class<E> enumClass) {
return new OMG<E>(name, new EnumMap<E, String>(enumClass));
}
}
public static void main(String[] args) {
try {
Class c = Class.forName("test.Test$SETTINGS");
// alternatively you can use:
// Class<SETTINGS> c = SETTINGS.class;
System.out.println(Arrays.toString(c.getEnumConstants()));
OMG.create("foobar", c);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
I assumed that you want to pass any enum type to the class OMG and not only SETTINGS. If it should only be SETTINGS, you might as well just use SETTINGS directly in your code. This is why I moved the SETTINGS enum out of the OMG class.
Next, I added a generic type parameter E to the class OMG, so OMG does not directly depend on SETTINGS. To enable easier initialization, I added a static factory method to OMG, which also uses a generic type parameter E. It only receives the name and the class objects which matches E. You need the class objects, since in Java you cannot directly use the generic type parameters for reflection.
Also, I replaced the HashMap by an EnumMap, since EnumMap is an optimized map implementation when the key is an enum.
Finally, the initialization of the OMG class: If you really need to create the class object from the name of the class, using reflection, you can use the code as is. Note that this will produce a warning. However, most of the time you want to use the class objects directly, like in the commented line of code. If you use this second method, you will not get a warning and you can also omit the try-catch block.
Thanks to #PaulBoddington I solved the issue as follows.
public class Test {
public static void main(String[] args) {
try {
Class<?> c = Class.forName("path.to.OMG" + "$" + "SETTINGS");
Object[] enumConstants = c.getEnumConstants();
HashMap<Object, String > configuration = new HashMap<>();
for (Object enumConstant: enumConstants){
configuration.put(enumConstant, enumConstant.key);
}
OMG omg = new OMG("blah", configuration);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
The use case for people wondering is that OMG is a module in the system which is configurable and also has to allow from a developers point of view new settings to be added easily. This is why settings and their value is kept in a HashMap < SETTING , STRING > and SETTING is an enum containing the key in the configuration file under which the setting should be found as well as other information - default value of example. The OMG class also has a
String getSettingValue(SETTING setting){
return settingsMap.get(setting);
}
method which returns the value for a setting and is what is exposed by the module.
This means that if a new setting has to be added to the component I just have to create a new instance of the SETTINGS enum and thats it. During creation if the server has not send a value for this setting I can either use the default or crash. On the other hand once the component is instantiated I have immediate access to the new setting without touching the existing code.
Please share your opinion on this architecture couse it is for a school project and I highly doubt the teacher will actually look into it and tell me if it is reasonable or not.
Thank you

How to create and then instantiate POJO classes dynamically?

Certain specifications of my project require me to create POJO classes from information provided via an excel sheet or JSON; then creating objects of that class with relevant information at hand that will be used later in the code.
Extracting relevant data from excel sheets and JSON is not an issue. I was even able to create POJO classes dynamically thanks to this answer. But I'm unsure if it is possible to create objects of this class. As this guy mentioned in his above answer that -
But the problem is: you have no way of coding against these methods,
as they don't exist at compile-time, so I don't know what good this
will do you.
Is it possible to instantiate the class created in the above answer? If so, how? If not, what are other alternatives to this problem? Or should I change my approach regarding this specification and think of some other option?
You can use reflection to instantiate the generated classses and access the provided methods.
Probably in your situation I would go for something like below. This could not be post as a comment. So posting here.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GenericDTO {
private Map<String, List<Object>> resultSetMap = new HashMap<String, List<Object>>() ;
public void addAttribute(String attributeName, Object attributeValue) {
if(resultSetMap.containsKey(attributeName)) {
resultSetMap.get(attributeName).add(attributeValue);
} else {
List<Object> list = new ArrayList<Object>();
list.add(attributeValue);
resultSetMap.put(attributeName, list);
}
}
public Object getAttributeValue(String key) {
return (resultSetMap.get(key) == null) ? null : resultSetMap.get(key).get(0);
}
public List<Object> getAttributeValues(String key) {
return resultSetMap.get(key);
}
}
You can use it like:
GenericDTO dto = new GenericDTO();
dto.addAttribute("aa", 1);
dto.addAttribute("aa", "aa");
dto.addAttribute("bb", 5);
System.out.println(dto.getAttributeValue("bb"));
System.out.println(dto.getAttributeValues("aa"));

How can I store Java types, allowing only some specific ones?

Lets assume I want to have a class that acts a descriptor for records, where each record has a set of attributes.
Each attribute has a unique name and should have a specific type that corresponds to a certain Java type such as Integer, String, Short, Double, ...
The list of possible types should be restricted such as I support only Integer and String for instance.
private HashMap<String, Class> attributeList = new HashMap<String, Class>();
In the above example the HashMap is a list of attributes where as the key is the attribute name and the value should be the type of the attribute (Integer or String).
What would be the best way to restrict the definition of the value of the Hashmap?
You could of course use wrapper methods to add elements to the map, and do a check for Integer and Sring there. But then you only get runtime errors. I agree with you that restricting the type to get static errors is much better.
For that, I would actually not use Integer.class and String.class, but an enum:
enum Types { String, Integer };
private Map<String, Types> attributeList = new HashMap<String, Types>();
UPDATE:
Come to think of it, there is another (but more complicated) solution, if you have to stick to Class objects: You can use the fake enum pattern, that is use a set of constants (usually the integers 2^i are used) like an enum. So you could define your Class objects as the constants. That of course does not guarantee that no other class objects are put into the map. That's why Joshua Bloch item 30 says "Use enums instead of int constants". But you can then use the Checker Framework to pull an additional type system over your constants using the Fake Enum checker:
#SuppressWarnings("fenum:assignment.type.incompatible")
public class TypeEnum {
public static final #Fenum("Types") Class INT_CONST = Integer.class;
public static final #Fenum("Types") Class STR_CONST = String.class;
}
Then you can define your map with a restriction on the type Class:
private HashMap<String, #Fenum("Types") Class> attributeList
= new HashMap<String, #Fenum("Types") Class>();
Of course, you would need to include the Fenum Checker into your compiler.
How about subclass HashMap and override the put method, throwing an exception when an unsupported type is used? (Untested... just off the top of my head.)
class MyAttributes extends HashMap<String, Class> {
private Set<Class> allowedTypes;
public MyAttributes() {
allowedTypes = new HashSet<Class>();
allowedTypes.add(Integer.class);
}
public Class put(String key, Class value) {
if(!allowedTypes.contains(value)) {
throw new UnsupportedTypeException(); // <-- Your new exception type.
}
return super.put(key, value);
}
}
As I see it, you have three options:
Use the definition as you have it, and when you pull the value check that it's one of the correct types.
Subclass the HashMap and enforce the type limits in said subclass when adding the elements.
Have multiple maps, one for each type you want to allow, typed appropriately.
Each option has advantages and disadvantages, and which one you should use should be determined by how you will use it.
How about method overload?
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
public class CarrierDate<T> {
private T localDate;
private CarrierDate(T localDate) {
this.localDate = localDate;
}
public T getLocalDate() {
return localDate;
}
public static CarrierDate<LocalDate> instance(LocalDate date) {
return new CarrierDate<>(date);
}
public static CarrierDate<LocalDateTime> instance(LocalDateTime date) {
return new CarrierDate<>(date);
}
public static CarrierDate<OffsetDateTime> instance(OffsetDateTime date) {
return new CarrierDate<>(date);
}
}

Categories