鉴于以下代码:
public class MyObject {
String myProperty;
public MyObject(String propertyValue) {
myProperty=propertyValue;
}
}
和
public class Main {
public static void main(String[] args) {
ArrayList<MyObject> objects = new ArrayList<MyObject>();
objects.add(new MyObject("first"));
objects.add(new MyObject("second"));
objects.add(new MyObject("third"));
// Now do Task A and Task B
}
}
现在我正在寻找以下方法:
任务A:查找myProperty等于“秒”的所有对象。 有什么像
ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ?
任务B:从列表中提取不同的myProperty值,这意味着我想得到一个包含(“first”,“second”,“third”)的数组 有什么像
ArrayList propertyValues = objects.getPropertyValues(myProperty) ?
我知道可以通过循环遍历ArrayList来解决任务A和B,但我想知道是否有更好的方法/已经内置于Eclipse中的内容?感谢任何提示: - )
请注意我不想使用外部库(我目前正在Android上开发并希望保持我的应用程序很小)。
答案 0 :(得分:1)
如果您需要第一个(任务A),则可能表明ArrayList
不是您应该使用的最佳数据结构。此类访问权限应该考虑使用Map
或MultiMap
(在Apache Commons Collections中实施)。
但是......如果你真的需要这种东西。几个图书馆派上用场。
最近受欢迎的是Guava。另一个是LambdaJ,似乎更专业:
// Task A
filter(having(on(MyObject.class).getPropertyValue(), equalTo("second")), objects);
// Task B
convert(objects, new PropertyExtractor("propertyValue"));
// or even
extract(objects, on(MyObject.class).getPropertyValue());
(我没有机会编译/运行我输入的代码,所以请不要过于严格)
答案 1 :(得分:0)
...但是,然后让我说我正在寻找没有外部库的Java的最佳方式?
在这种情况下,您最好的方法是编写循环。
可以基于对命名字段的反射访问来构建解决方案,但代码并不简单,当然也不具备性能。
...所以我想如果我介绍一个我只使用一个小东西的外部库,我会被队友杀死。
你的同事也倾向于用反射来杀死你。确保您的生殖仍然附着(:-))的最佳方法是编写循环。
答案 2 :(得分:0)
Eclipse不会直接帮助你完成这项任务 - 它只能帮助创建程序 - 它本身不会创建。
如果无法向项目添加新库,则可以编写自己的通用解决方案。但是,我强烈建议您考虑添加一些常见的库,如之前建议的Guava或Apache Commons。
您尝试实现的两个任务可以更一般地描述为过滤和映射(也称为选择,投影)。 过滤可以通过使用谓词来推广 - 谓词 - 一个简单的函数,它将返回对象是否应该包含在新集合中。 映射可以通过一个泛型函数来实现,该函数接受一个源对象(在您的情况下,MyObject),并返回另一个类型的对象(在您的情况下为String)。
这些set(集合)操作更容易被语言支持,其中一些编译到JVM,例如python(jython),groovy和scala。但我猜这不是一个为项目使用不同语言的选择。
所以我将演示如何在Java中实现它,尽管语法有点笨拙,因为我们将为谓词和转换器使用匿名类。
在What is the best way to filter a Java Collection?有一个简单的DIY过滤示例,所以我将在示例中使用它。
我们需要的两个接口:
public interface Convertor<FROM, TO> {
TO convert(FROM from);
}
public interface Predicate<T> {
boolean apply(T type);
}
实际的“图书馆”:
import java.util.ArrayList;
import java.util.Collection;
public class CollectionUtils {
public static <FROM, TO> Collection<TO> select(Collection<FROM> from, Convertor<FROM, TO> convertor) {
Collection<TO> result = new ArrayList<TO>();
for (FROM fromItem: from) {
result.add(convertor.convert(fromItem));
}
return result;
}
public static <T> Collection<T> filter(Collection<T> target, Predicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
}
现在我们可以轻松完成这两项任务:
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
ArrayList<MyObject> objects = new ArrayList<MyObject>();
objects.add(new MyObject("first"));
objects.add(new MyObject("second"));
objects.add(new MyObject("third"));
// Now do Task A and Task B
// Task A: Filter
Collection<MyObject> filtered = CollectionUtils.filter(objects, new Predicate<MyObject>() {
@Override
public boolean apply(MyObject myObject) {
return myObject.myProperty.equals("second");
}
});
for (MyObject myObject: filtered) {System.out.println(myObject.myProperty);}
System.out.println();
// TASK B: Map/Select
Collection<String> transforemd = CollectionUtils.select(objects, new Convertor<MyObject, String>() {
@Override
public String convert(MyObject from) {
return from.myProperty;
}
});
for (String str: transforemd) {System.out.println(str);}
}
}
现在更改谓词以过滤其他对象,或者创建不同的字符串,甚至是其他类型而不是脚本,这将非常简单:只需更改apply()和convert()函数即可! (哦,好吧,一些泛型提示:))。
免责声明:代码未经过全面测试,仅用于演示,可能还有其他一些问题(例如为新集合分配ArrayList)。这就是使用经过良好测试和调试的第三方库通常更好的原因!
答案 3 :(得分:0)
不可否认,以下是我的工作广告,但它确实适合您的问题。
首先,有人必须做这项工作。要么你自己做,也就是自己编写必要的循环,要么你有一些库为你做的工作。
我不知道这里建议的其他库,但是如果你想看看http://tbull.org/projects/util4j/,这是我自己编写的一个小库,许可证允许它从你需要的东西源代码并将其包含在您自己的源代码中。
在这种方法中,使用了专门制作的Grepper
和Mapper
s,因此不需要反射。它确实非常像Amitay Dobo已发布的内容,但是这个lib提供了更多功能的操作模式,包括从Iterator
读取输入元素和延迟grepping / mapping。
任务A:查找myProperty等于“second”的所有对象。是否有类似
的内容ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ?
这可以像
那样完成import org.tbull.util.Collections;
import org.tbull.util.Grepper;
private static class PropertyGrepper implements Grepper<MyObject> {
public final String property;
public PropertyGrepper(String property) {
this.property = property;
}
public @Override boolean grep(MyObject element) {
return element.myProperty.equals(property);
}
}
List<MyObject> filteredObjects = Collections.grep(new PropertyGrepper("second"), objects);
任务B:从列表中提取不同的myProperty值,这意味着我想得到一个包含(“first”,“second”,“third”)的数组。是否有像
ArrayList propertyValues = objects.getPropertyValues(myProperty) ?
import org.tbull.util.Collections;
import org.tbull.util.Mapper;
private static class PropertyExtractor implements Mapper<MyObject, String> {
public @Override String map(MyObject element) {
return element.myProperty;
}
}
List<String> propertyValues = Collections.map(new PropertyExtractor(), objects);
免责声明:此代码未经测试。必须能够访问myProperty
才能使其正常工作,无论是public
还是由getter函数提供。
当然,您可以使用匿名内部类来简化或公开实现Grepper / Mapper以获得可重用性。