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

类似的;

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

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

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


当前回答

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

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

new Object().setName("John")

其他回答

Eclipse集合

如果您正在使用Eclipse Collections,则可以使用anyssatisfy()方法。如果可能的话,在ListAdapter中调整列表或将列表更改为ListIterable。

ListIterable<MyObject> list = ...;

boolean result =
    list.anySatisfy(myObject -> myObject.getName().equals("John"));

如果要经常执行这样的操作,最好提取一个方法来回答该类型是否具有该属性。

public class MyObject
{
    private final String name;

    public MyObject(String name)
    {
        this.name = name;
    }

    public boolean named(String name)
    {
        return Objects.equals(this.name, name);
    }
}

您可以使用替代形式anySatisfyWith()和方法引用。

boolean result = list.anySatisfyWith(MyObject::named, "John");

如果不能将List更改为ListIterable,下面是如何使用ListAdapter。

boolean result = 
    ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");

注意:我是Eclipse集合的提交者。

这里有一个使用番石榴的解决方案

private boolean checkUserListContainName(List<User> userList, final String targetName){

    return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
        @Override
        public boolean apply(@Nullable User input) {
            return input.getName().equals(targetName);
        }
    });
}

如果你正在使用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>包含名称为name的MyObject,此方法将返回true。如果你想对getName().equals(name)的每个myobject执行一个操作,那么你可以尝试这样做:

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

其中o表示MyObject实例。

或者,正如评论所建议的(感谢MK10),你可以使用Stream#anyMatch方法:

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

这是如何使用Java 8+做到这一点:

boolean isJohnAlive = list.stream().anyMatch(o -> "John".equals(o.getName());

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的缺点以及其他语言如何做得更好的例子。