I'm trying to implement a generic interface with concrete types, but the java compiler is forcing me to instantiate it as raw. This is a mock-up of my code:
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("thing", "extra");
Worker<String, String> worker = new Worker<>();
worker.execute(map);
}
public class Worker<K, V> {
public void execute(Map<K, V> map) {
IDao<K, V> dao = new Dao();
dao.doThing(map);
}
}
public interface IDao<K, V> {
void doThing(Map<K, V> map);
}
public class Dao implements IDao<String, String> {
public void doThing(Map<String, String> map) {
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String newKey = key.toUpperCase();
System.out.println(newKey " " entry.getValue());
}
}
}
This code works as expected if I change IDao<K, V> dao = new Dao();
to IDao dao = new Dao()
, but this isn't good practice and I'd like to avoid it. I don't understand why it's illegal to declare the types at instantiation like this.
CodePudding user response:
This...
public class Worker<K, V> {
public void execute(Map<K, V> map) {
IDao<K, V> dao = new Dao();
dao.doThing(map);
}
}
seems wrong to me.
The Worker
class allows for generic key/value parameters for the Map
, but, you're instantiating an instance of Dao
which is constrained to <String, String>
. This seems like a basic violation of the contract.
Personally, I might change this so that the instance of IDao
is injected into the worker, for example...
public static class Worker<K, V> {
private IDao<K, V> dao;
public Worker(IDao<K, V> dao) {
this.dao = dao;
}
public void execute(Map<K, V> map) {
dao.doThing(map);
}
}
nb: This could be an abstract
factory, which had a abstract
method something like abstract protected IDao<K, V> getDao();
and then you'd have to provide some kind concrete implementation to support it, but it's basically boiling down to the same thing
Then you'd simply be able to call it doing something like...
Map<String, String> map = new HashMap<>();
map.put("thing", "extra");
Worker<String, String> worker = new Worker<>(new Dao());
worker.execute(map);
Of course, if you didn't want to do that, then you'd have to remove the generic constraints for Worker
and require that any caller pass it a Map
constrained to <String, String>
public static class Worker {
public void execute(Map<String, String> map) {
IDao<String, String> dao = new Dao();
dao.doThing(map);
}
}
But now, where's the benefit?