【问题标题】:Efficient way to add multiple value in Map Collection在地图集合中添加多个值的有效方法
【发布时间】:2019-09-03 11:02:29
【问题描述】:

我正在尝试在 redshift 中创建多个用户(例如使用密码“xyz”创建用户“abc”)。同样,当用户创建 redshift 时,我将这些用户名和密码存储在本地 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 中成功创建所有用户后,我存储“用户名|密码”。在Redshift上成功创建后存储用户名|密码是否可行?这种方法对我有用。但是我该如何改进这种方法呢?如何简化这种方法?

【问题讨论】:

    标签: java dictionary collections java-8 java-stream


    【解决方案1】:

    首先,我建议您避免使用collection.stream().forEach() 构造,因为Stream-API 应该遵循non-interference 原则。此外,您可以将forEach 方法调用到任何Iterable,包括ListSet

    现在回到你的问题。更改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
    }
    

    【讨论】:

    • 正确地制作课程证书是完美的。因为我在我的流中添加元素,所以我违反了不干扰原则,对吗?
    • @user10144071:您不应该修改Stream 中的另一个可变源。阅读更多Parallelism - Side Effects
    【解决方案2】:

    可能是这样的:

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

    其中 createUsernamePass 是一种创建数据对象的方法,其中包含您的用户名、密码和加密密码,而 store(userNamePass) 是一种执行数据库插入的方法。

    (这是在iPad上写的,没有测试,但可以考虑这个想法)

    你也可以并行执行这个,让它更快。

    【讨论】:

    • 制作两种方法很有意义,一种用于存储,另一种用于创建用户。
    猜你喜欢
    • 2013-05-31
    • 2022-07-19
    • 2014-10-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-08
    • 2014-12-18
    相关资源
    最近更新 更多