Java 在具有给定名称的不变列表中查找元素

Java 在具有给定名称的不变列表中查找元素,java,data-structures,Java,Data Structures,在Java中,我创建了一个对象集合(类型相同),每个对象都包含一个名为name的字符串字段。集合、对象及其名称都是在构造函数中生成的,永远不会更改。我希望能够轻松找到具有给定名称的对象 class Program { final Collection<Foo> foos; Program() { foos = new HashSet<>(); // Note: I'm willing to use another type of

在Java中,我创建了一个对象集合(类型相同),每个对象都包含一个名为
name
的字符串字段。集合、对象及其
名称都是在构造函数中生成的,永远不会更改。我希望能够轻松找到具有给定
名称的对象

class Program { 
    final Collection<Foo> foos; 

    Program() {
        foos = new HashSet<>();   // Note: I'm willing to use another type of collection
        foos.add(new Foo("First", 7));
        foos.add(new Foo("Qwerty", 4));
    }

    get(String name) {
        // how?
    }
}

class Foo {
    final String name;
    int size;

    Foo(String name, int size) {
         this.name = name;
         this.size = size;
    }
}
类程序{
最终收集食物;
程序(){
foos=newhashset();//注意:我愿意使用另一种类型的集合
添加(新的Foo(“第一”,7));
添加(新的Foo(“Qwerty”,4));
}
获取(字符串名称){
//怎么做?
}
}
福班{
最后的字符串名;
整数大小;
Foo(字符串名称,整数大小){
this.name=名称;
这个。大小=大小;
}
}

我可以想出几种方法来获得具有给定
名称的Foo
。我可以制作一个
映射
,但这似乎比实际需要的内存要多得多(每个字符串都必须在内存中复制,并且有一个全新的数据结构)。或者,我可以创建一个简单的foreach循环,但这是O(n)效率,我正在寻找O(1)或接近它的值。

首先,正如注释中所指出的,所以不要期望集合的内存效率更高

其次,您声明在使用映射时必须复制
字符串
实例。事实并非如此。Java通过引用而不是通过值传递非基本类型的实例,因此,如果您像这样创建映射:

map.put(foo.getName(), foo);
map.put("alice", new Foo("alice"));
Foo
中的
name
字段指向的
String
实例将与映射键指向的实例完全相同。你没有浪费任何记忆。还要注意,即使是这样的事情:

map.put(foo.getName(), foo);
map.put("alice", new Foo("alice"));
不会导致字符串在内存中重复。一般来说,您应该小心不要做出太多这样的假设,因为不仅JVM,而且编译器都可能在背后进行大量优化。关注功能性和可读性,然后在发现瓶颈时进行优化*插入关于过早优化的陈词滥调*

最后,
Collection
接口不提供
get
方法,因为它没有任何意义。集合就是对象的集合。它对它们一无所知,它只是“收集”它们。从任意集合中检索对象与要求某人打开未知项目的抽屉并取出其中的蓝色物品是一样的。上述人员必须查看每个项目才能找到蓝色的项目,但可能有多个蓝色的项目,因此不仅需要线性时间才能找到蓝色的项目,还可能有重复的项目(不在
集合中),如果是,您可能不知道您得到的是哪一个蓝色的项目

现在,另一方面,
Map
提供了一种将某种唯一标识符与它“收集”的每个项目相关联的方法(请注意,
Map
不是
Collection
)。这正是您试图在
程序
类中手动实现的。您需要一个
Foo
对象的集合,并希望通过名称唯一地标识它们。这就是地图的用途

请注意,如果您想支持重复,只需要使用给定名称获取一些
Foo
,那么您需要寻找一个多重映射,您可以通过将名称映射到
Foo
对象列表来对其进行非常粗略的实现(请注意,您必须自己进行必要的空检查和列表实例化):

Map=。。。;

如果坚持使用
集合
,则必须对其进行迭代以检索对象(因为
集合
接口不保证迭代顺序)。但是,一般来说,在需要成员资格测试的情况下使用集合(我有这个
Foo
,它是否存在于我的集合中?),和映射用于需要检索给定唯一标识符的对象的情况。

请注意,
HashSet
在幕后使用
HashMap
。使用
Map
而不是
Set
@SotiriosDelimanolis any
Set
在幕后使用一个
Map
Set
s并不是真正用于检索的。请注意,您可以从
Map
实现中创建任何类型的
Set
。您真的需要所有您想要的吗?通过遵循以下步骤,您可以避免不必要的时间浪费。