从对象列表中获取最新更新记录时使用地图的正确方法是什么

时间:2019-06-20 21:40:39

标签: java performance

下面两种从列表中获取最新更新记录的方法有什么区别,哪种更好?为什么?

示例- 假定消息列表包含按顺序记录的记录,其中消息对象将是:

Message
{
   Integer id ;
   String name ;
}

列表中名为“邮件”的值包含

[1 , "a"],[2, "b"],[1 , "b"],[1, "c"]

结果应仅包含这两个记录-

[2, "b"] ,[1, "c"]

解决方案1-

Map<Integer,String> latestMessage = new HashMap<>();
             for (Message m : messages) { 
                 latestMessage.put(m.getId(), m.getName());
             }

解决方案2-

Map<Integer,String> latestMessage = new HashMap<>();
            for (Message m : messages) { 
                         if(!latestMessage.containsKey(m.getId())) {
                         latestMessage.put(m.getId(), m.getName());
                         }
                         else {
                             latestMessage.replace(m.getId(), m.getName())  ;
                         }
                     }

2 个答案:

答案 0 :(得分:0)

我会选择前一个(put),因为您没有使用该消息,甚至没有尝试合并 (由于Java 8和{{3} }方法):

您也不做类似的事情:

Map<String, List<String>> map = ...;
for (Message m : messages)
  map.computeIfAbsent(m.getId(), k -> new ArrayList<>()).add(m.getName());

如果是的话,您应该使用StreamgroupingBy,如下所示:

messages.stream()
        .collect(groupingBy(Message::getId, Message::getName));

回到您的两个用例:

  • 使用put也更短,更容易理解:后者(containsKey + put / replace)会更难理解(不是 ,虽然如此,但您仍然必须阅读代码才能理解它。)
  • 就性能而言,使用put的速度应比检查映射是否存在的速度快一点,因为您需要进行更多的操作。我不会为此付出很大的努力,但是您将不得不编写一个基准测试(使用JMH)以比较哪个更好。

TL; DR::除非可以证明containsKey + put / replace更好,否则使用看跌期权。

答案 1 :(得分:0)

我尝试了以下代码来查看您所提供的方法之间的性能差异:

public class MapPerformanceTest {
    public static void main(String[] args) {
        Map<Integer, Integer> map = new HashMap();
        // fill the map with 50000 entities
        int count = 50000;
        for (int i = 0; i < count; i++) {
            // value doesn't matter
            map.put(i, getRandom(0, count));
        }
        // fill a set with one million entities
        Set<Integer> set = new HashSet();

        int setSize = 1000000;
        for (int i = 0; i < setSize; i++) {
            set.add(getRandom(0, count));
        }

        // use the set to test performance
        long startTime = System.nanoTime(), endTime = 0;
        Iterator<Integer> iterator = set.iterator();
        while (iterator.hasNext()) {
            int next = iterator.next();
            map.put(next, getRandom(0, count));
        }
        endTime = System.nanoTime();
        System.out.println(String.format("PUT: %d", endTime - startTime));

        startTime = System.nanoTime();
        iterator = set.iterator();
        while (iterator.hasNext()) {
            int next = iterator.next();
            if(!map.containsKey(next)) {
                map.put(next, getRandom(0, count));
            }
            else {
                map.replace(next, getRandom(0, count))  ;
            }
        }
        endTime = System.nanoTime();
        System.out.println(String.format("REPLACE: %d", endTime - startTime));
    }

    private static int getRandom(int min, int max) {
        return ThreadLocalRandom.current().nextInt(min, max + 1);
    }
}

运行上述代码时,它将在控制台上打印以下内容:

PUT: 17171025
REPLACE: 18274190

这意味着第一种方法的性能稍好。