次のように使用するのに役立つユーティリティメソッドがありますConcurrentMap.putIfAbsent
。
public static <K, V> V putIfAbsent(
ConcurrentMap<K, V> map, K key, Callable<V> task) {
try {
V result = map.get(key);
if (result == null) {
V value = task.call();
result = map.putIfAbsent(key, value);
if (result == null) {
result = value;
}
}
return result;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
今、私はそのような異質なマップに対処しなければなりません:
private ConcurrentMap<Class<?>, List<ClassHandler<?>>> handlerMap;
それにハンドラを追加するメソッド:
public <T> void addHandler(Class<T> c, ClassHandler<? super T> handler) {
putIfAbsent(handlerMap, c, new Callable<List<ClassHandler<?>>>() {
@Override
public List<ClassHandler<?>> call() throws Exception {
return new CopyOnWriteArrayList<>();
}
}).add(handler);
}
これまでのところは問題ありませんが、クラスを処理しようとすると問題が発生します。たとえば、次のようになります。
Class<String> c = String.class;
List<ClassHandler<?>> handlers = handlerMap.get(c);
if (handlers != null) {
for (ClassHandler<?> c : handlers) {
handler.handle(c);
}
}
ただし、次のコードはコンパイルされません。
error: method handle in class ClassHandler<T> cannot be applied to given types;
handler.handle(c);
required: Class<CAP#1>
found: Class<String>
reason: actual argument Class<String> cannot be converted to Class<CAP#1> by method invocation conversion
where T is a type-variable:
T extends Object declared in class ClassHandler
where CAP#1 is a fresh type-variable:
CAP#1 extends Object from capture of ?
1 error
を使用するとコードはコンパイルhandler.handle((Class) c)
されますが、未チェックの警告が表示されます。注釈を追加することはできますが@SuppressWarnings("unchecked")
、他に良い方法がなければこれが最後の選択肢になります。
この問題について何か考えはありますか?