我可以让这个 java pluck() 方法更安全吗?
我编写了这个实用函数:
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);
我的问题是,如果调用者得到的类型错误,则不会引发异常,直到调用者尝试从列表中获取对象为止。理想情况下,我想从 pluck
方法本身抛出一个 ClassCastException
。但是,我没有找到在运行时访问列表类型的方法。
我可以使用一些技巧来确保调用者不会得到无效列表吗?
编辑:因此,使用我得到的反馈,一个安全的实现是:
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 发布以来,该项目不再维护(JSR 335,JEP 126)。
I wrote this utility function:
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;
}
I copied the idea from underscore.js. The use case is:
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);
My problem is that if the caller gets the type wrong, no exception is thrown until the caller tried to get an object from the list. Ideally, I'd like to throw a ClassCastException
from the pluck
method itself. However, I don't see a way to access the type of the list on run time.
Is there some trick I can use to make sure the caller doesn't end up with an invalid list?
Edit: So using the feedback I got, a safe implementation would be:
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;
}
But actually lambdaj seems to do what I wanted, so I guess I'll use that. Thanks mike!
Disclaimer: LambdaJ ( @GoogleCode | @GitHub ) - This project is not maintained anymore since the release of JDK8 (JSR 335, JEP 126).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您可以将您的签名更改为如下:
您拥有列表类型和字段类型。
You can change your signature to as follows:
The you have the list type and field type.
为什么不这样定义签名:
这将:
1)强制客户端提供他想要“提取”的字段的类型,以便您可以在方法中进行正确的类型检查。
2) 强制客户端提供一个从中“提取”的通用列表,这样就可以防止另一个错误源(客户端提供包含不同类型对象的列表)。
我认为这是尽可能安全的..
Why dont you define the signature like this:
This would:
1) Force the client to supply the type of the field he wants to "pluck", so you can do proper type-checking in your method.
2) Force the client to supply a generic list from which to "pluck", so you prevent another error-source (the client supplying a list that contains objects of different types).
I think this is as safe as it can get..
无效列表是什么意思?如果您的意思是他们尝试将其转换为不是的东西,那么请尝试将声明更改为
public static;列表pluck(String fieldName, List列表)
。我对
However, I don't see a way to access the type of the list on run time.
注释感到困惑。然而,如果我理解正确的话:运行时没有“类型”,因为Java中的泛型是通过“擦除”实现的。这意味着编译器会在编译时检查它是否有效,然后将其转换为常规转换,就像我们在泛型之前所做的那样。他们认为这是实现向后和向前兼容性所必需的。What do you mean by invalid list? If you mean that they try to cast it to something it is not then try changing the declaration to
public static <T> List<T> pluck(String fieldName, List<T> list)
.I'm confused by the
However, I don't see a way to access the type of the list on run time.
comment. However, if I understand you correctly then: there is no "type" at runtime because generics in Java are implemented by "erasure". This means that the compiler checks at compile time that it works, and then turns it into regular casts like we had before generics. This was necessary they felt to enable backward and forward compatibility.您应该对类型参数使用泛型,并传入返回类型的类对象:
通常,当您收到有关类型参数不安全强制转换的警告时,您应该查看是否可以将其替换为对
类.cast
You should use generics for the type parameter, and pass in the class object of the return type:
Generally, when you get a warning about an unsafe cast to a type parameter, you should see if you can replace it with a call to
Class.cast
你可以尝试 Google 集合库提供的一个,而不是维护一个新的:Collections2.transform 像这样
you can try the one given by Google collections library instead of maintaining a new one: Collections2.transform like this
通过 Google 的 Guava 集合库,您可以使用
Collections2.transform()
。用法
给定一个接口/类,例如称为
Entity
,您的类可以实现/扩展它。现在您可以检索每个
Entity
的 ID 列表。这是你能得到的最安全的。这满足适当的 OOP 原则和 Java 5-7。
实现相同的效果
在 Java 8 中,您可以使用流、映射和 lambda或
With Google's Guava collections library, you can use
Collections2.transform()
.Usage
Given an interface/class, e.g. called
Entity
, your class can implement/extend this.Now you can Retrieve a list of each
Entity
's IDs.This is the safest you can get. This satisfies proper OOP principles and Java 5-7.
In Java 8, you can achieve the same effect with a stream, map, and lambda
or
不确定你在问什么,但你可以尝试:
Not sure what you are asking, but you could try:
您可以将该列表转换为
java.lang.reflect.ParameterizedType
并检查getActualTypeArguments()
返回的数组是否包含您需要的类。除此之外,你就不走运了。You can cast the list to a
java.lang.reflect.ParameterizedType
and checking that the array returned bygetActualTypeArguments()
contains the class you need. Other than that, you're out of luck.