我实际上有几个问题。
我有一个 Dog 类,其中包含以下实例字段:
private int id;
private int id_mother;
private int id_father;
private String name="";
private String owner="";
private String bDate="";
我还有一个归档类可以实例化 Dog 并将Dog对象放入ArrayList。
我正在尝试在存档中编写一个方法,该方法将整数作为ID并查看ArrayList,并返回包含该ID的对象。
private Dog getDog(int id){
Dog dog = new Dog();
int length=getSize();
int i=0;
dog=al.get(i);
i++;
while(dog.getId()!=id && i<length)
dog=al.get(i);
i++;
if(dog.getId()!=id)
dog=null;
return dog;
}//end getDog
此方法存在两个问题(我使用的其他方法)。首先它没有用,我看不出原因。我正在循环(可能)arraylist中的所有对象,因为在循环结束后,检查循环是否完成,因为它用完了要搜索的对象,或者因为它找到了具有给定ID的对象。其次,这似乎是一个非常耗时的过程。有没有办法加快这个速度?
答案 0 :(得分:44)
假设您已经正确地为Dog编写了一个equals方法,根据Dog的id进行比较,返回列表中项目的最简单方法如下:
if (dogList.contains(dog)) {
return dogList.get(dogList.indexOf(dog));
}
这比其他方法的性能密集程度要低。在这种情况下,您根本不需要循环。希望这会有所帮助。
P.S您可以使用Apache Commons Lang为Dog编写一个简单的equals方法,如下所示:
@Override
public boolean equals(Object obj) {
EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());
return builder.isEquals();
}
答案 1 :(得分:16)
while
适用于while
之后的表达式或块。
你没有阻止,所以你的时间以表达式dog=al.get(i);
while(dog.getId()!=id && i<length)
dog=al.get(i);
之后的所有事情只发生一次。
没有理由新建一只狗,因为你从来没有使用过新生的狗;你立即将数组中的狗分配给你的狗参考。
如果你需要获取一个键的值,你应该使用Map,而不是数组。
编辑:这是为什么?
OP的评论:
关于不必制作狗的新实例的另一个问题。如果我只是从数组列表中取出对象的副本,那么我怎么能从数组列表中取出它而没有我放置它的对象?我刚刚注意到我没有将while循环括起来。
Java引用及其引用的对象是不同的东西。它们非常像C ++引用和对象,尽管Java引用可以像C ++指针一样重新指向。
结果是Dog dog;
或Dog dog = null
为您提供了指向无对象的引用。 new Dog()
创建可以指向的对象。
之后使用dog = al.get(i)
表示引用现在指向al.get(i)
返回的狗引用。理解,在Java中,永远不会返回对象,只引用对象(它们是内存中对象的地址)。
你新建的狗的指针/参考/地址现在已经丢失,因为没有代码引用它,因为所指对象被你从al.get()
得到的指示物所取代。最终,Java垃圾收集器将销毁该对象;在C ++中,你已经“泄露”了记忆。
结果是你确实需要创建一个可以引用Dog的变量;你不需要用new
创建一只狗。
(实际上你不需要创建引用,因为你真正应该做的是返回一个Map从其get()函数返回的内容。如果Map没有在Dog上进行参数化,就像这样: Map<Dog>
,然后您需要从get转换回报,但您不需要引用:return (Dog) map.get(id);
或者如果参数化了地图return map.get(id)
。那一行是你的整个函数,对于大多数情况来说,它比迭代一个数组要快。)
答案 2 :(得分:16)
为了提高操作性能,如果您总是想要通过某个唯一标识符查找对象,那么您可以考虑使用Map<Integer,Dog>
。这将按键提供恒定时间查找。您仍然可以使用地图values()
迭代对象本身。
一个快速的代码片段,可以帮助您入门:
// Populate the map
Map<Integer,Dog> dogs = new HashMap<Integer,Dog>();
for( Dog dog : /* dog source */ ) {
dogs.put( dog.getId(), dog );
}
// Perform a lookup
Dog dog = dogs.get( id );
如果您在列表中执行多个相同性质的查找,这将有助于加快速度。如果您只是进行一次查找,那么无论如何都会产生相同的循环开销。
答案 3 :(得分:13)
你必须遍历整个阵列,没有改变。但是,你可以做得更轻松
for (Dog dog : list) {
if (dog.getId() == id) {
return dog; //gotcha!
}
}
return null; // dog not found.
或没有新的for循环
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getId() == id) {
return list.get(i);
}
}
答案 4 :(得分:1)
我有兴趣看到原始海报使用的风格避免了早期退出。单次入场;单出口(SESE)是一种有趣的风格,我还没有真正探索过。已经很晚了,我有一瓶苹果酒,所以我写了一个解决方案(没有经过测试),没有提前退出。
我应该使用迭代器。不幸的是java.util.Iterator
在get方法中有副作用。 (由于其例外后果,我不喜欢Iterator
设计。)
private Dog findDog(int id) {
int i = 0;
for (; i!=dogs.length() && dogs.get(i).getID()!=id; ++i) {
;
}
return i!=dogs.length() ? dogs.get(i) : null;
}
请注意i!=dogs.length()
表达式的重复(可能已选择dogs.get(i).getID()!=id
)。
答案 5 :(得分:0)
如果必须获取不是ID的属性。我会使用CollectionUtils。
Dog someDog = new Dog();
Dog dog = CollectionUtils(dogList, new Predicate() {
@Override
public boolean evaluate(Object o)
{
Dog d = (Dog)o;
return someDog.getName().equals(d.getName());
}
});
答案 6 :(得分:0)
我使用java 8 lambdas
解决了这个问题int dogId = 2;
return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0);
答案 7 :(得分:0)
List<YourClass> list = ArrayList<YourClass>();
List<String> userNames = list.stream().map(m -> m.getUserName()).collect(Collectors.toList());
输出: [“ John”,“ Alex”]