我写了这个效用函数:
public static <T> List<T> pluck(String fieldName, List list)
throws NoSuchFieldException, IllegalAccessException {
if (list.isEmpty()) {
return new ArrayList<T>();
}
Class c = list.get(0).getClass();
Field f = c.getField(fieldName);
ArrayList<T> result = Lists.newArrayList();
for (Object object : list) {
result.add((T) f.get(object));
}
return result;
}
我从underscore.js复制了这个想法。用例是:
ArrayList<Person> people = new ArrayList<Person>;
people.add(new Person("Alice", "Applebee"));
people.add(new Person("Bob", "Bedmington"));
people.add(new Person("Charlie", "Chang"));
List<String> firstNames = pluck("firstName", people);
我的问题是,如果调用者输入的类型错误,则在调用者尝试从列表中获取对象之前不会抛出任何异常。理想情况下,我想从ClassCastException
方法本身抛出pluck
。但是,我没有看到在运行时访问列表类型的方法。
我可以使用一些技巧来确保调用者最终没有无效列表吗?
编辑:因此,使用我得到的反馈,安全的实施将是:
public static <T,F> List<F> pluck(String fieldName, Class<F> fieldType,
List<T> list, Class<T> listType)
throws NoSuchFieldException, IllegalAccessException {
Field f = listType.getField(fieldName);
ArrayList<F> result = new ArrayList<F>();
for (T element : list) {
result.add(fieldType.cast(f.get(element)));
}
return result;
}
但实际上lambdaj似乎做了我想要的,所以我想我会用它。谢谢迈克!
免责声明: LambdaJ (@GoogleCode | @GitHub) - 自JDK8发布以来,该项目不再维护({{3} },JSR 335)。
答案 0 :(得分:2)
为什么不定义这样的签名:
public static <T, U> List<T> pluck(String fieldName, Class<T> fieldType, List<U> list);
这会:
1)强制客户端提供他想要“拔出”的字段类型,这样你就可以在你的方法中进行适当的类型检查。
2)强制客户端提供一个“拔出”的通用列表,这样就可以防止出现另一个错误源(客户端提供包含不同类型对象的列表)。
我认为这样可以安全......
答案 1 :(得分:2)
您可以将签名更改为:
public static <T, F> List<F> pluck(String fieldName, Class<F> fieldType,
List<T> list, Class<T> listType)
您有列表类型和字段类型。
答案 2 :(得分:1)
无效列表是什么意思?如果你的意思是他们试图将它转换为某种东西,那么请尝试将声明更改为public static <T> List<T> pluck(String fieldName, List<T> list)
。
我对However, I don't see a way to access the type of the list on run time.
评论感到困惑。但是,如果我理解正确,那么:没有&#34;类型&#34;在运行时,因为Java中的泛型是由&#34; erasure&#34;实现的。这意味着编译器在编译时检查它是否正常工作,然后将其转换为普通的转换,就像我们在泛型之前一样。他们认为这是实现向后和向前兼容的必要条件。
答案 3 :(得分:1)
您应该使用泛型作为type参数,并传入返回类型的类对象:
public static <TItem, TResult> List<TResult> pluck(String fieldName, List<TItem> list, Class<TResult> resultType)
throws NoSuchFieldException, IllegalAccessException {
if(list.isEmpty()) return new ArrayList<TResult>();
Class c = list.get(0).getClass();
Field f = c.getField(fieldName);
ArrayList<TResult> result = new ArrayList<TResult>();
for(Object object : list) {
result.add(resultType.cast(f.get(object)));
}
return result;
}
通常,当您收到关于对类型参数的不安全强制转换的警告时,您应该看看是否可以通过调用Class.cast
来替换它
答案 4 :(得分:1)
您可以尝试使用Google集合库提供的库而不是维护新的集合库:Collections2.transform就是这样
Collection<Y> yourCollection...
...
Collection<X> expected = Collections2.transform(yourCollection, new Function<Y, X>() {
public X apply(Y element) {
return element.getX();
}
}
答案 5 :(得分:1)
使用Google的Guava馆藏库,您可以使用Collections2.transform()
。
给定一个接口/类,例如名为Entity
,您的类可以实现/扩展它。
public abstract class Entity {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
public interface Entity {
long getId();
}
现在,您可以检索每个Entity
ID的列表。
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
public class Main {
public static void main(String[] args) {
List<Entity> entities = ...
List<Long> ids = pluckIds(entities);
}
public static <E extends Entity> List<Long> pluckIds(List<E> list) {
return new ArrayList<Long>(Collections2.transform(list, new Function<E, Long>() {
public Long apply(E entity) {
return entity.getId();
}
});
}
}
这是最安全的。这满足了正确的OOP原则和Java 5-7。
在Java 8中,您可以使用stream,map和lambda
实现相同的效果public static <E extends Entity> List<Long> pluckIds(List<E> list) {
return list.stream().map(e -> e.getId()).collect(Collectors.toList());
}
或
public static <T,F> List<F> pluck(String fieldName, Class<F> fieldType,
List<T> list, Class<T> listType) throws NoSuchFieldException,
IllegalAccessException, IllegalArgumentException {
Field f = listType.getDeclaredField(fieldName);
f.setAccessible(true);
return list.stream().map(e -> {
try { return fieldType.cast(f.get(e)); } catch (Exception e1) { return null; }
}).collect(Collectors.toList());
}
答案 6 :(得分:0)
不确定你在问什么,但你可以尝试:
Class c = list.get(0).getClass();
if (!c.equals(Person.class))
throw new ClassCastException();
答案 7 :(得分:0)
您可以将列表转换为java.lang.reflect.ParameterizedType
并检查getActualTypeArguments()
返回的数组是否包含您需要的类。除此之外,你运气不好。