如何确定一个对象列表中是否包含具有指定字段值的内容?

30

我有一个从数据库中接收到的DTO列表,它们都有一个ID。我想确保我的列表中包含一个具有指定ID的对象。显然,在这种情况下创建一个带有期望字段的对象是没有帮助的,因为contains()需要调用Object.equals()方法,而它们不会相等。

我想到了一个解决方案:创建了一个接口HasId,在所有的DTO中实现它,并通过一个新类继承ArrayList,该类具有contains(Long id)方法。

public interface HasId {
    void setId(Long id);
    Long getId();
}

public class SearchableList<T extends HasId> extends ArrayList<T> {
    public boolean contains(Long id) {
        for (T o : this) {
            if (o.getId() == id)
                return true;
        }
        return false;
    }
}

但在这种情况下,我不能将List和ArrayList强制转换为SearchableList...

我可以忍受这一点,但希望确保我没有重复造轮子。

编辑('16年10月):

当然,随着Java 8中lambda的引入,实现这一点的方法非常简单:

list.stream().anyMatch(dto -> dto.getId() == id);

9
我确定你的意思是“重新发明轮子”。 - Nishan
为什么不直接搜索List<HasID>呢? - Ray Tayek
Nishan,这正是我所说的,这是一个翻译问题:DRay Tayek,哇,如此简单而优雅的想法甚至没有跨越我的脑海,我会确保尝试一下,谢谢。 - Sergey
不确定是否可以将List<DTO>强制转换为List<HasId>。 - Sergey
2
感谢您使用anyMatch()方法进行编辑。 - PrestigeDev
6个回答

51

我建议创建一个简单的静态方法,就像你所写的那样,没有任何额外的接口:

public static boolean containsId(List<DTO> list, long id) {
    for (DTO object : list) {
        if (object.getId() == id) {
            return true;
        }
    }
    return false;
}

为了更好的代码可读性,我会将for和if语句中的括号删除。在我看来这是个好习惯。无论如何,感谢提供这个方法! - wzieba
嗯,就性能而言不是最佳选择,我认为@medopal的解决方案更好。 - Choletski
1
@Choletski,这里的性能有什么问题吗? 假设我们不使用并行计算,您无法做得比O(N)更好。 - Mikita Belahlazau

8

我建议您在SearchableDto中覆盖equals方法,代码应该类似于:

public boolean equals(Object o){
    if (o instanceof SearchableDto){
        SearchableDto temp = (SearchableDto)o;
        if (this.id.equals(temp.getId()))
            return true;
    }
    return false;
}

在这种情况下,如果具有相同的“id”,则contains应该正常工作;

2

我认为你的方法有些过于复杂了。

你说:

我有一个从数据库接收到的DTO列表,它们都有一个ID。

那么你应该使用一个DTO类来保存这些项。如果是这样,请在该类中添加id getter和setter:

public class DTO implements HasId{
    void setId(Long id);
    Long getId();
}

这已经足够遍历ArrayList并搜索所需id。仅为添加“compare-id”功能扩展ArrayList类似乎对我来说过于复杂了。@Nikita Beloglazov做出了很好的示例。您甚至可以更加概括:

public boolean containsId(List<HasId> list, long id) {
    for (HasId object : list) {
        if (object.getId() == id) {
            return true;
        }
    }
    return false;
}

1

这是我在深度优先搜索 GetUnvisitedNeighbour 函数中使用的内容。

    public static int GetUnvisitedNeighbour(int v)
{
    Vertex vertex = VertexList.stream().filter(c -> c.Data == v).findFirst().get();
    int position = VertexList.indexOf(vertex);
    ...
}

我曾在C#上工作过。在C#中,Lambda表达式比Java更容易使用。

可以使用filter函数为元素的属性添加条件。

然后根据逻辑使用findFirst().get()findAny.get()


0

您的需求对我来说不是很清楚。当您说“确保我的列表包含具有指定ID的对象”时,您是想要:

  1. 检测是否存在该ID并采取相应措施
  2. 始终在结果中包含具有所需ID的DTO

大多数回答都假定您指的是第一种情况,但考虑问题时,鉴于问题的措辞,您也可能意味着第二种情况。您可以通过更改查询来包含所需的结果:

SELECT * FROM employee WHERE firstname = 'John' OR id = 42;

这是一个测试语句,我想确保我的Hibernate代码正确映射并从数据库中提取正确的值。 - Sergey
如果这只是一个特定的测试用例,那么为什么不只是循环遍历检索到的对象,并在找不到所需ID时使测试失败呢?为什么要让所有DTO实现HasId接口来做这件事呢? - Adriaan Koster

0
   public boolean containsId(List<HasId> list, long id) {
    boolean flag = false;
    for (HasId object : list) {
        if (object.getId() == id) {
           flag = true;
        }
    }
    return flag;
}

1
最好在标志值为真时中断“for each”循环,而不是一直循环到结束。 - jarvo69

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接