我想获取一个属性列表,意味着我有一个类User,它有一个属性名称,我有一个公共方法getName()来获取用户名,现在我的问题是我要创建一个采用通用列表的方法和方法名称,并借助流API获取类的属性列表。
表示如果我在测试方法中传递用户和方法名称'getName'的列表,则返回用户名列表。
public static boolean test(List<?> propertyList) throws Exception{
Class<?> c = Class.forName(propertyList.get(0).getClass().getCanonicalName());
Method method = c.getDeclaredMethod(methodName);
!propertyList.stream().map(c::method).allMatch(new HashSet<>()::add);
}
答案 0 :(得分:1)
您不能像使用Class
一样使用Method
将::
对象和c::method
对象放在一起。您可以使用method::invoke
来表达动态调用,但不幸的是,这将与预期的类型Function
不兼容,因为Method.invoke
可以抛出已检查的异常。
因此,您可以使用封装动态调用的lambda表达式并捕获反射异常:
public static boolean test(List<?> propertyList, String methodName) throws Exception{
Method method = propertyList.get(0).getClass().getDeclaredMethod(methodName);
return !propertyList.stream().map(x -> {
try {
return method.invoke(x);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("invoking "+method, ex);
}
}).allMatch(new HashSet<>()::add);
}
如果使用Method
作为Function
是代码中反复出现的问题,则可以使用Java的内置功能创建工厂方法来创建动态类:
public static boolean test(List<?> propertyList, String methodName) throws Exception {
Method method = propertyList.get(0).getClass().getDeclaredMethod(methodName);
return !propertyList.stream().map(toFunction(method)).allMatch(new HashSet<>()::add);
}
public static Function toFunction(Method m) throws IllegalAccessException {
return MethodHandleProxies.asInterfaceInstance(Function.class,
MethodHandles.lookup().unreflect(m));
}
但请注意,您的方法存在一些概念上的缺陷。它依赖于List
不为空,并对第一个列表元素的类型施加了非预期的约束。列表可以包含具有公共基类型作为声明元素类型的不同实际类型的元素。即使所有元素都具有相同的类型,getDeclaredMethod
也只会搜索最具体的类并忽略继承的方法。
换句话说,即使使用"toString"
作为方法名称也可能会失败,因为该过程不会查找Object.toString
,因此可能无法找到该方法,或者它可能在第一个元素中找到方法类型对于列表中的其他元素而言过于具体。
更好的设计是让调用者提供类型:
public static <T> boolean test(
List<? extends T> propertyList, Class<T> type, String methodName) throws Exception {
Method method = type.getMethod(methodName);
return !propertyList.stream().map(toFunction(method)).allMatch(new HashSet<>()::add);
}
这允许传入具有声明的元素类型比列类型更具体的列表来搜索方法,并且还具有比声明元素类型更具体的类型的特定元素,甚至支持空列表。
请注意,getMethod
的搜索会考虑继承的方法,但只会查找public
方法。