问题:我们需要获取不同类对象的(String)键。 为了实现可扩展性,我们希望将Method配置为用于获取键字符串 - 而不是使用intanceOf实现许多if-else ...
天真的解决方案(带有示例数据)是:
public static String getKey(Object object, Map<Class<?>, Method> keySources) {
Method source = keySources.get(object.getClass());
if (source == null) {
return null;
}
try {
return (String) source.invoke(object);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("Error at 'invoke': " + e.getMessage(), e);
}
}
public static void main(String[] args) {
Map<Class<?>, Method> keySources = new HashMap<>();
try {
keySources.put(String.class, String.class.getMethod("toString"));
keySources.put(Thread.class, Thread.class.getMethod("getName"));
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException("Error at 'getMethod': " + e.getMessage(), e);
}
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
所需的解决方案就像:
public static String getKey(Object object, Map<Class<?>, Function<Object, String>> keySources) {
Function<Object, String> source = keySources.get(object.getClass());
if (source == null) {
return null;
}
return source.apply(object);
}
public static void main(String[] args) {
Map<Class<?>, Function<Object, String>> keySources = new HashMap<>();
keySources.put(String.class, String::toString);
keySources.put(Thread.class, Thread::getName);
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
但是String::toString
正在提出编译错误:The type String does not define toString(Object) that is applicable here
约束:我们无法修改类,因为它们是生成的。
答案 0 :(得分:0)
我设法让你的代码通过编译并运行。我不确定为什么它适用于lambda表达式,但不能用于方法引用。
也许有更好的方法可以做到这一点。
public static <T> String getKey(T object, Map<Class<?>, Function<? extends Object, String>> keySources)
{
Function<T, String> source = (Function<T, String>) keySources.get(object.getClass());
if (source == null) {
return null;
}
return source.apply(object);
}
public static void main (java.lang.String[] args) throws Exception
{
Map<Class<?>, Function<? extends Object, String>> keySources = new HashMap<>();
keySources.put(String.class, s -> s.toString());
keySources.put(Thread.class, (Thread t) -> t.getName());
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
答案 1 :(得分:0)
Function<Object, String>
是一个接受Object
的函数,换句话说任意对象作为参数,所以像String::toString
这样的函数需要它的参数是String
个实例无法履行合同。这很容易修复,因为您可以使用Object::toString
来代替Thread::getName
,这需要参数为Thread
个实例,但没有这样的替换。
由于您确保参数由于映射键而属于正确类型,因此您可以通过将每个特定函数转换为执行类型转换的Function<Object,String>
来解决此问题:
public static <T,R> void put(Class<T> cl,
Function<T,R> f, Map<Class<?>,Function<Object,R>> map) {
map.put(cl, obj -> f.apply(cl.cast(obj)));
}
public static String getKey(Object object,
Map<Class<?>, Function<Object, String>> keySources) {
return keySources.getOrDefault(object.getClass(), x -> null).apply(object);
}
public static void main(String[] args) {
Map<Class<?>, Function<Object, String>> keySources = new HashMap<>();
put(String.class, String::toString, keySources);
// or put(String.class, Function.identity(), keySources);
put(Thread.class, Thread::getName, keySources);
System.out.println(getKey("test", keySources));
System.out.println(getKey(new Thread("name"), keySources));
}
答案 2 :(得分:-1)
Function
选择一个与签名不匹配的参数。
尝试使用不带参数的Callable
并返回值