Эффективный способ добавить несколько значений в коллекцию карт - PullRequest
1 голос
/ 12 апреля 2019

Я пытаюсь создать несколько пользователей в красном смещении (скажем, создать пользователя "abc" с паролем "xyz"). И то же самое, когда пользователь создал красное смещение, я храню эти имена пользователей и их пароль в локальной базе данных MySQL, но пароль в зашифрованном формате. Мой текущий подход:

Map<String, String> uNamePassForDB = new HashMap<>();
Map<String, String> uNamePassForRedshift = new HashMap<>();

listOfUsers.stream().forEach(u -> {
        String pass = //some random password generator;
        String encryptedPassword = //encrpts the password (i.e. pass)
        uNamePassForDB.put(u, encryptedPassword);
        uNamePassForRedshift.put(u, pass);
}

uNamePassForRedshift.entrySet().stream().forEach(e -> {
      // creating redshift connection and executing create user command
}

uNamePassForRedshift.entrySet().stream().forEach(e -> {
      // storing the encrypted password in my local MySQL Database
}

В настоящее время я сохраняю имя пользователя и пароль после того, как все пользователи успешно созданы в красном смещении. Можно ли сохранить имя пользователя | пароль, если он успешно создан в Redshift? Этот подход работает для меня. Но как я могу улучшить этот подход? Как упростить этот подход?

Ответы [ 2 ]

1 голос
/ 12 апреля 2019

Во-первых, я предлагаю вам избегать конструкции collection.stream().forEach(), поскольку Stream-API должен следовать принципу невмешательства . Более того, вы можете вызывать метод forEach для любого Iterable, включая List или Set.

Теперь вернемся к вашей проблеме. Проблема изменения значений Map обсуждалась много раз, и я все еще удивляюсь, что JDK не дает четкого решения этой проблемы. Лично я считаю, что одним из лучших подходов является простая итерация и замена самих значений. Даже в версии + это законный путь:

for (String user: listOfUsers) {
    String pass = "random password";
    String encryptedPassword = "encrypted password";
    uNamePassForDB.put(user, encryptedPassword);
    uNamePassForRedshift.put(user, pass);
}

Поскольку вы пометили , попробуйте декларативно представить, что результат Stream будет будет , а не делать (это отличие от процедурного for-loop мышления). Единственный способ, который мне известен, это не нарушает принцип невмешательства и не вызывает побочных эффектов (генерация пароля все еще сомнительна):

// Each Stream should do ONE thing

final List<Credential> credentials = listOfUsers.stream()
    .map(user -> new Credential(user, /* random password */ ))
    .collect(Collectors.toList());

final Map<String, String> uNamePassForDB = credentials.stream()
    .collect(Collectors.toMap(
                 Credential::getUser,                                     // key
                 Credential::getEncryptedPassword));                      // value

final Map<String, String> uNamePassForRedshift = credentials.stream()
    .collect(Collectors.toMap(
                 Credential::getUser,                                     // key
                 Credential::getPassword));                               // value

Где создан неизменный класс Credential для помощи:

public static class Credential {
    private final String user;
    private final String password;
    private final String encryptedPassword;

    public Credential(final String user, final String password) {
        this.user = user;
        this.password = password;
        // I suggest this to avoid inconsistency
        this.encryptedPassword = /* encrypt password */           
    }

    // getters
}
0 голосов
/ 12 апреля 2019

Примерно так:

listOfUsers.stream().map(this::createUsernamePass).forEach(this::store);

Где createUsernamePass - это метод создания объекта данных, содержащий ваше имя пользователя, пароль и зашифрованный пароль, а хранилище (userNamePass) - это метод, выполняющий вставки в базу данных.

(Это написано на iPad и не проверено, но идея может быть рассмотрена)

Возможно, вы можете выполнить это параллельно, но сделайте его быстрее.

...