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

Rud*_*haw 177 java search contains list

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

就像是;

if(list.contains(new Object().setName("John"))){
    //Do some stuff
}
Run Code Online (Sandbox Code Playgroud)

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

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

Jos*_*h M 219

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

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

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

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

true如果List<MyObject>包含MyObject带有名称的a ,则此方法将返回name.如果你想对每个MyObjects 执行操作getName().equals(name),那么你可以尝试这样的事情:

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

Where o代表一个MyObject实例.

  • 更短更容易理解:```return list.stream().anyMatch(o - > o.getName().equals(name));``` (46认同)
  • @EricJablow也许你应该评论**所有**不执行`null`检查的答案,而不是只有一个(我的). (5认同)
  • 我与@MK10结合但我会使用`java.util.Objects`进行nullsafe比较`return list.stream().anyMatch(o - > Objects.euqals(o.getName(),name);`如果你想要检查流中的对象是否为null,可以在anyMatch之前添加`.filter(Objects :: nonNull)`. (3认同)
  • 那么,第二个例子应该是“public boolean”。另外,如果“o.getName()”可以为“null”,您可能需要使用“Objects.equals()”。 (2认同)

Jam*_*unn 79

你有两个选择.

1.首选,最好是覆盖Object类中的`equals()`方法.

比方说,你有这个Object类:

public class MyObject {
    private String name;
    private String location;
    //getters and setters
}
Run Code Online (Sandbox Code Playgroud)

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

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

MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
Run Code Online (Sandbox Code Playgroud)

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

  • 您正在使用名称和位置来检查是否相等,但您只想检查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;
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以扩展ArrayList(或其他一些集合),然后将自己的方法添加到它:

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

不幸的是,它没有更好的方法.


Bri*_*new 25

谷歌番石榴

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

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

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

如下所述,Java 8及更高版本内置的java.util.Stream框架提供了类似的功能.


Aar*_*lla 20

Collection.contains()通过调用equals()每个对象来实现,直到返回一个true.

所以实现这一点的一种方法是覆盖,equals()但当然,你只能有一个等于.

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

构建在VM之上的其他语言也内置了这些语言.例如,在Groovy中,您只需编写:

def result = list.find{ it.name == 'John' }
Run Code Online (Sandbox Code Playgroud)

Java 8也使我们的生活变得更轻松:

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

如果您关心这样的事情,我建议您阅读"Beyond Java"一书.它包含许多关于Java的众多缺点以及其他语言如何做得更好的例子.


Deb*_*kia 19

二进制搜索

您可以使用Collections.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());
            }
        });
Run Code Online (Sandbox Code Playgroud)

如果对象不在集合中,它将返回负数,否则它将返回index对象的对象.通过这种方式,您可以搜索具有不同搜索策略的对象.


Gab*_*lBB 16

这是使用Java 8+的方法:

boolean johnExistance = list.stream().anyMatch(o -> o.getName().equals("John"));
Run Code Online (Sandbox Code Playgroud)

  • 尝试了上面 Josh 的基于过滤器的答案,但 Intellij 还建议了您的 anyMatch 答案。伟大的! (4认同)
  • 请翻转字符串相等性检查以避免潜在的空指针异常 `"John".equals(o.getName())` (4认同)

小智 8

地图

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


Cra*_*lin 6

Eclipse集合

如果您正在使用Eclipse Collections,则可以使用该anySatisfy()方法.如果可能的话,要么适应你的要求List,ListAdapter要么改变List成a ListIterable.

ListIterable<MyObject> list = ...;

boolean result =
    list.anySatisfy(myObject -> myObject.getName().equals("John"));
Run Code Online (Sandbox Code Playgroud)

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将备用表单anySatisfyWith()与方法引用一起使用.

boolean result = list.anySatisfyWith(MyObject::named, "John");
Run Code Online (Sandbox Code Playgroud)

如果你不能改变List成a ListIterable,这就是你的使用方式ListAdapter.

boolean result = 
    ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Run Code Online (Sandbox Code Playgroud)

注意:我是Eclipse ollections的提交者.


use*_*383 5

Predicate

如果您不使用Java 8或库来为您提供更多处理集合的功能,那么您可以实现比您的解决方案更可重用的东西.

interface Predicate<T>{
        boolean contains(T item);
    }

    static class CollectionUtil{

        public static <T> T find(final Collection<T> collection,final  Predicate<T> predicate){
            for (T item : collection){
                if (predicate.contains(item)){
                    return item;
                }
            }
            return null;
        }
    // and many more methods to deal with collection    
    }
Run Code Online (Sandbox Code Playgroud)

我正在使用类似的东西,我有谓词接口,我将它的实现传递给我的util类.

以我的方式做这件事有什么好处?你有一个方法来处理任何类型集合中的搜索.如果你想通过不同的字段搜索,你不必创建单独的方法.你需要做的是提供不同的谓词,一旦它不再有用就可以被销毁

如果你想使用它,你需要做的就是调用方法并定义tyour谓词

CollectionUtil.find(list, new Predicate<MyObject>{
    public boolean contains(T item){
        return "John".equals(item.getName());
     }
});
Run Code Online (Sandbox Code Playgroud)