我想检查一个列表是否包含一个对象,该对象具有具有特定值的字段。现在,我可以使用循环来遍历和检查,但我很好奇是否有更高效的代码。

类似的;

if(list.contains(new Object().setName("John"))){
    //Do some stuff
}

我知道上面的代码没有做任何事情,它只是粗略地演示了我想要实现的目标。

另外,澄清一下,我不想使用简单循环的原因是,这段代码将进入一个循环,这个循环在一个循环中,而这个循环又在一个循环中。为了可读性,我不想一直在这些循环中添加循环。所以我想知道是否有什么简单的替代方案。


当前回答

你有两个选择。

1. 首选的方法是重写Object类中的' equals() '方法。

比方说,你有这样一个Object类:

public class MyObject {
    private String name;
    private String location;
    //getters and setters
}

现在我们假设你只关心MyObject的名字,它应该是唯一的,所以如果两个MyObject有相同的名字它们应该被认为是相等的。在这种情况下,您可能希望重写' equals() '方法(以及' hashcode() '方法),以便它比较名称以确定是否相等。

一旦你这样做了,你可以检查一个集合是否包含一个名为“foo”的MyObject,就像这样:

MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);

但是,在以下情况下,这可能不适合你:

您同时使用名称和位置来检查是否相等,但您只想检查集合中是否有具有特定位置的' MyObject '。在本例中,您已经重写了' equals() '。 MyObject是API的一部分你没有自由去改变它。

如果是这两种情况,你需要选择2:

2. 编写自己的实用方法:

public static boolean containsLocation(Collection<MyObject> c, String location) {
    for(MyObject o : c) {
        if(o != null && o.getLocation.equals(location)) {
            return true;
        }
    }
    return false;
}

或者,你可以扩展ArrayList(或其他集合),然后添加你自己的方法:

public boolean containsLocation(String location) {
    for(MyObject o : this) {
        if(o != null && o.getLocation.equals(location)) {
                return true;
            }
        }
        return false;
    }

不幸的是,没有更好的办法了。

其他回答

包含在内部使用等号的方法。因此,您需要根据需要重写类的equals方法。

顺便说一句,这看起来语法不正确:

new Object().setName("John")

谷歌番石榴

如果您正在使用Guava,您可以采用功能方法并执行以下操作

FluentIterable.from(list).find(new Predicate<MyObject>() {
   public boolean apply(MyObject input) {
      return "John".equals(input.getName());
   }
}).Any();

看起来有点啰嗦。但是谓词是一个对象,您可以为不同的搜索提供不同的变体。注意库本身是如何分离集合的迭代和希望应用的函数的。您不必为特定的行为重写equals()。

如下面所述,Java 8及以后版本中内置的Java .util. stream框架提供了类似的功能。

二分查找

您可以使用集合。binarySearch用于搜索列表中的元素(假设列表是有序的):

Collections.binarySearch(list, new YourObject("a1", "b",
                "c"), new Comparator<YourObject>() {

            @Override
            public int compare(YourObject o1, YourObject o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

如果该对象不存在于集合中,它将返回一个负数,否则将返回该对象的索引。有了它,您可以使用不同的搜索策略搜索对象。

Map

你可以创建一个Hashmap<String, Object>,使用其中一个值作为键,然后查看yourHashMap.keySet().contains(yourValue)是否返回true。

collect .contains()通过在每个对象上调用equals()来实现,直到其中一个对象返回true。

实现这个的一种方法是重写equals()当然,你只能有一个equals。

因此,像Guava这样的框架为此使用谓词。iterable。Find (list, predicate),您可以通过将测试放入谓词来搜索任意字段。

其他构建在VM之上的语言都内置了这个功能。例如,在Groovy中,你可以简单地写:

def result = list.find{ it.name == 'John' }

Java 8也让我们的生活变得更简单:

List<Foo> result = list.stream()
    .filter(it -> "John".equals(it.getName())
    .collect(Collectors.toList());

如果你关心这些事情,我建议你读《超越Java》这本书。它包含了许多关于Java的缺点以及其他语言如何做得更好的例子。