Java List.contains(字段值等于x的对象)

问题

我想检查aList是否包含具有特定值的字段的对象。现在,我可以使用循环来检查,但我很好奇是否有更多的代码有效。

就像是;

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

我知道上面的代码没有做任何事情,只是为了大致展示我想要实现的目标。

另外,为了澄清,我不想使用简单循环的原因是因为此代码当前将进入循环内循环内部的循环。为了便于阅读,我不想继续为这些循环添加循环。所以我想知道是否有任何简单的(ish)替代品。


#1 热门回答(147 赞)

#Streams

如果你使用的是Java 8,也许可以尝试这样的方法:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}

或者,你可以尝试这样的事情:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}

如果List<MyObject>包含aMyObject,则该方法将返回true,名称为name。如果你想在976932066sgetName().equals(name)上执行每个操作,那么你可以尝试这样的事情:

public void perform(final List<MyObject> list, final String name){
    return list.stream().filter(o -> o.getName().equals(name)).forEach(
            o -> {
                //...
            }
    );
}

Whereo代表aMyObject实例。


#2 热门回答(72 赞)

你有两个选择。
1.首选,最好是覆盖Object类中的equals()方法。

比方说,你有这个Object类:

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

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

完成此操作后,你可以检查Collection是否包含名为"foo"的MyObject,如下所示:

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

但是,如果符合以下条件,则可能不适合你:

  • 你正在使用名称和位置来检查是否相等,但你只想检查Collection是否具有某个位置的"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;
    }

不幸的是,没有更好的方法来解决它。


#3 热门回答(23 赞)

#Google Guava

如果你使用的是Guava,则可以采用功能方法并执行以下操作

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

看起来有点冗长。但是谓词是一个对象,你可以为不同的搜索提供不同的变体。请注意库本身如何分离集合的迭代和要应用的函数。你不必为特定行为覆盖equals()

如下所述,Java 8及更高版本中内置的52425334框架提供了类似的功能。