Ich denke, dies ist mein größter Fehler und mir wird langsam klar, dass ich mich in meiner Web-App unzählige Male wiederholt habe.

Jedes Mal, wenn ich vergleichen möchte, ob eine Eigenschaft aus einer Liste mit einer anderen Eigenschaft einer Liste identisch ist, mache ich eine doppelte for-Schleife.

Natürlich ist das im Moment nicht schlecht für meine Website, aber sobald sie Millionen von Benutzern hat, wird sie langsamer.

Das ist mein typischer Fehler:

In diesem Fall habe ich ein List<String> mit den Benutzernamen der protokollierten Benutzer und möchte die vollständigen Benutzerinformationen für jeden Benutzer an das Frontend zurückgeben.

Dies scheint sehr schlecht zu sein, da ich alle Benutzer durchlaufen muss, obwohl ich nur die Informationen für die Online-Benutzer abrufen muss.

Kann mir jemand dabei helfen? Ist das schlechte Praktiken? Was kann ich tun?

 @Autowired
private ActiveUsers activeUsers;

 @RequestMapping(value = "/loggedUsers", method = RequestMethod.GET)
public @ResponseBody List<User> getLoggedUsers() {
    List<User> users = User.getUsers();
    List<User> onlineUsers = new ArrayList<>();
    for(User user : users) {
        for(String username : activeUsers.getUsers()) {
            if(username.equals(user.getUsername())) {
                onlineUsers.add(user);
            }
        }
    }
    return onlineUsers;
}
1
user9658240 17 Apr. 2018 im 14:50

4 Antworten

Beste Antwort

Verwenden Sie ein Map<String,User>. Lassen Sie User.getUsers() das Map zurückgeben (es sollte wahrscheinlich zwischengespeichert werden, damit Sie dieses Map nicht jedes Mal generieren müssen, wenn Sie diese Methode aufrufen). Der Schlüssel wäre der Benutzername und der Wert wäre das entsprechende User.

Jetzt können die verschachtelten Schleifen durch eine einzelne Schleife ersetzt werden:

List<User> getLoggedUsers() {
    Map<String,User> users = User.getUsers();
    List<User> onlineUsers = new ArrayList<>();
    for (String username : activeUsers.getUsers()) {
        User user = users.get(username);
        if(user != null) {
            onlineUsers.add(user);
        }
    }
    return onlineUsers;
}

Mit Java 8 kann dies vereinfacht werden, um:

List<User> getLoggedUsers() {
    Map<String,User> users = User.getUsers();
    return activeUsers.getUsers()
                      .stream()
                      .map(users::get)
                      .filter(Objects::nonNull)
                      .collect(Collectors.toList());
}
4
Eran 17 Apr. 2018 im 12:00

Wie ich es machen würde:

@Autowired
private ActiveUsers activeUsers;

@RequestMapping(value = "/loggedUsers", method = RequestMethod.GET)
public @ResponseBody List<User> getLoggedUsers() {
    final List<User> users = User.getUsers();
    final List<User> activeUsersList = activeUsers.getUsers();

    return users.stream()
                .filter(user -> activeUsersList.contains(user))
                .colect(Collectors.toList());
}

Die Verwendung von Streams ab Java 8 ist sehr hilfreich und nicht schwer zu verstehen.

0
Alex Bondor 17 Apr. 2018 im 12:18

Verwenden Sie diese Codezeile:

Set<User> onlineUsers = users.stream().filter(
    user -> activeUsers.getUsers().contains(user.getUserNmae())).collect(Collectors.toSet());
0
Yassine Badache 17 Apr. 2018 im 13:09

Konvertieren Sie List<User> users in Map<String,User> users (wobei der Schlüssel der Benutzername ist). Dann können Sie 1 für Schleife überspringen und zur Zeit O (1) abrufen.

Map<> myset = User.getUsers();

Jetzt können Sie eine einzelne for-Schleife einchecken und prüfen, ob activeUsers users enthält.

0
Pankaj Singhal 18 Apr. 2018 im 03:13