8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

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

Xavier 2月前

245 0

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

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

类似于;

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

我知道上面的代码没有任何作用,它只是为了大致演示我想要实现的目标。

另外,需要澄清的是,我不想使用简单循环的原因是,此代码当前将进入循环内部,而循环内部又包含循环。为了便于阅读,我不想继续在这些循环中添加循环。所以我想知道是否有任何简单的替代方案。

帖子版权声明 1、本帖标题:Java List.contains(字段值等于 x 的对象)
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Xavier在本站《class》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 如果你正在使用 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();
    }
    

    如果 true 包含 List<MyObject> 名为 的 ,则 MyObject 此方法将返回 name MyObject 每个 执行操作 getName().equals(name) ,那么您可以尝试以下操作:

    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()));
    }
    
  • 那么,第二个示例应该是 public boolean。此外,如果 o.getName() 可以为 null,则可能需要使用 Objects.equals()。

  • 我只是个偏执的程序员。我处理过一些项目,其中有人对空值处理得非常随意,所以我倾向于采取防御措施。最好确保项目永远不为空。

  • @EricJablow也许你应该对不执行空检查的所有答案进行评论,而不是仅仅一个(我的)。

  • Inze 2月前 0 只看Ta
    引用 6

    甚至更短更容易理解:return list.stream().anyMatch(o -> o.getName().equals(name));

  • 我同意@MK10 但我会使用 java.util.Objects 进行 nullsafe 比较返回 list.stream().anyMatch(o -> Objects.euqals(o.getName(), name); 如果您想检查流中的对象是否为 null,您可以在 anyMatch 之前添加 .filter(Objects::nonNull)。

  • 你有两个选择。

    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;
        }
    

    不幸的是,没有更好的办法解决这个问题。

  • 我认为你忘记了 if(o != null && o.getLocation.equals(location)) 中 getter 的括号

  • 使用 Java 8+ 的方法如下:

    boolean isJohnAlive = list.stream().anyMatch(o -> "John".equals(o.getName());
    
  • 尝试了 Josh 上面提供的基于过滤器的答案,但 Intellij 还建议使用您的 anyMatch 答案。太棒了!

  • 请翻转字符串相等性检查以避免潜在的空指针异常 \'John\'.equals(o.getName())

  • 谷歌番石榴

    如果您使用 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

  • 引用 14

    或者,您可以使用 Iterables.any(list, predicate),它实际上是相同的,并且您可能会或可能不会在风格上喜欢它。

  • Collection.contains() 每个对象直到返回来 equals() 实现 true .

    因此,实现这一点的一种方法是覆盖, equals() 但当然,只能有一个等于。

    等框架 Guava 使用谓词来实现此目的。使用 Iterables.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 的诸多缺点以及其他语言的优缺点。

  • 引用 16

    因此,如果我覆盖添加到列表中的自定义对象的 equals 方法……我可以让它在某些类变量相同时返回 true 吗?

  • 不,equals() 背后的想法非常有限。它意味着检查“对象身份”——无论这对某些类的对象意味着什么。如果你添加了一个标志来指示哪些字段应该被包含,那么可能会导致各种麻烦。我强烈建议不要这样做。

  • 喜欢 groovy,那么“新”的 Java 8 Lambda 真的还不能给我们带来这种酷炫吗?def result = list.find{ it.name == 'John' } Oracle/JCP 应该因针对程序员的战争罪而被起诉。

  • 引用 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());
                }
            });
    

    如果对象不在集合中,它将返回负数,否则它将返回 index 对象的。通过这个,你可以用不同的搜索策略来搜索对象。

  • 对于不想使用 guava 的小型项目来说,这是一个很好的解决方案。但有一个问题,binarySearch 上的文档指出:“在进行此调用之前,必须根据指定的比较器将列表按升序排序。如果没有排序,结果将不确定”。但在某些情况下,根据所比较的内容,情况可能并非如此?

返回
作者最近主题: