我有一个本地商店中的用户列表,我需要每隔一段时间从远程用户列表中进行更新。基本上是:
EG。 远程列表:用户(1,真),用户(2,真),用户(4,真),用户(5,真)
本地列表:用户(1,真),用户(2,假),用户(3,真),用户(6,真)
新本地列表:用户(1,真),用户(2,真),用户(3,假),用户(4,真),用户(5,真),用户(6,假),< / p>
只是同步本地列表的简单案例。有没有更好的方法在纯Java中执行此操作而不是以下?我觉得我很难看自己的代码。
public class User {
Integer id;
String email;
boolean active;
//Getters and Setters.......
public User(Integer id, String email, boolean active) {
this.id = id;
this.email = email;
this.active = active;
}
@Override
public boolean equals(Object other) {
boolean result = false;
if (other instanceof User) {
User that = (User) other;
result = (this.getId() == that.getId());
}
return result;
}
}
public static void main(String[] args) {
//From 3rd party
List<User> remoteUsers = getRemoteUsers();
//From Local store
List<User> localUsers =getLocalUsers();
for (User remoteUser : remoteUsers) {
boolean found = false;
for (User localUser : localUsers) {
if (remoteUser.equals(localUser)) {
found = true;
localUser.setActive(remoteUser.isActive());
localUser.setEmail(remoteUser.getEmail());
//update
}
break;
}
if (!found) {
User user = new User(remoteUser.getId(), remoteUser.getEmail(), remoteUser.isActive());
//Save
}
}
for(User localUser : localUsers ) {
boolean found = false;
for(User remoteUser : remoteUsers) {
if(localUser.equals(remoteUser)) {
found = true;
localUser.setActive(remoteUser.isActive());
localUser.setEmail(remoteUser.getEmail());
//Update
}
break;
}
if(!found) {
localUser.setActive(false);
// Deactivate
}
}
}
答案 0 :(得分:7)
最好的方法是切换到不同的数据结构。 Map<Integer, User>
将是最好的,因为可能用户具有唯一标识ID。您选择的Map
实施可以是HashMap
(基本操作的预期O(1)
)或TreeMap
(O(log N)
)。
重要提示:您@Override equals(Object)
没有@Override hashCode()
!这是危险!你应该总是养成不要两者兼顾的习惯! (见:
Overriding equals and hashCode in Java
)
所以,假设你有Map<Integer, User> remoteUsers
和Map<Integer, User> localUsers
。
1.如果远程用户已在本地存在,请更新其字段
4.如果本地用户也出现在远程列表中,请更新其字段。(与1相同)
2.)如果本地尚不存在远程用户,请添加该用户。
查找来自User
的{{1}} remoteUsers
是否在localUsers
,O(1)
或O(log N)
可以使用简单containsKey
和{{ 1}}。
get
3.如果本地用户未出现在远程列表中,请取消激活或删除。
以下解决方案显示了这些更高级的数据结构的强大功能:
for (int id : remoteUsers.keys()) {
User local;
if (localUsers.containsKey(id)) {
local = localUsers.get(id);
else {
localUsers.put(id, local = new User(id));
}
local.updateFrom(remoteUsers.get(id));
}
此外,如果您遇到Set<Integer> toDeactivate = new TreeSet<Integer>();
toDeactivate.addAll(localUsers.keySet());
toDeactivate.removeAll(remoteUsers.keySet());
for (int id : toDeactivate) {
User local = localUsers.get(id);
local.deactivate();
localUsers.remove(id);
}
,您仍然可以使用List<User>
作为此处理的中间数据结构(基本上将Map<Integer, User>
转换为List<User>
,然后返回到Map<Integer, User>
)。与现在的List<User>
相比,它仍然会更快,因为它是O(N log N)
或O(N)
。
如果您坚持只使用列表,那么您可能希望将其设为O(N^2)
- 列表,这样您就可以对其进行Collections.sort
。您需要提供Collections.binarySearch
或制作Comparator<User>
,自然按User implements Comparable<User>
排序。这也是id
。
答案 1 :(得分:1)
您可以使用List.indexOf()
而不是遍历列表:
for (User remoteUser : remoteUsers) {
int index = localUsers.indexOf(remoteUser);
if (index >= 0) {
User localUser = localUsers.get(index);
localUser.setActive(remoteUser.isActive());
localUser.setEmail(remoteUser.getEmail());
//update
} else {
User user = new User(remoteUser.getId(), remoteUser.getEmail(), remoteUser.isActive());
//Save
}
}
答案 2 :(得分:1)
Langali:
假设Id唯一标识用户,我会为您提供一些建议:
public User { private final Key key; ... other variables public static class Key { private final int id; public Key(final int id) { } // hashcode (can be the id) // equals (as you had implemented) } }
Map<User.Key, User>;
get
和containsKey
方法查找您要查找的内容。List.contains的问题在于,在ArrayList上,它执行列表内容的完整扫描。如果您对第二个列表中的每个项目执行此操作,则表现为O(n ^ 2),这意味着当您将项目加倍时,将运算方法所需的时间乘以4。 HashMap的性能为O(log(n)),这意味着如果你有1000个对象,运行它所需的时间只会慢10倍(大约)。