[Java数据结构]Map的contiansKey和List的contains比较

Map的containskey方法使用哈希算法查找key是否存在,运算时间是常数;

List的contains方法是将元素在列表中遍历,运算时间和列表长度有关。

我使用两种不同SQL语句获取两种不同类型的结果集进行比较,发现两者差别很明显。

名称 类型 比较方法 耗时
两个含35,7282数据的map对比 map containsKey 101ms
两个含36,13962数据的list对比 list contains 46s455ms

 至于Map包含的数据量略少于map,是因为存在重复key,map把它过滤掉了,这在结果集比较时有一小段是缺乏证明的,需要用另外的手段再验证。

代码:

package com.ufo.leftjoin;

import java.security.MessageDigest;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.Logger;

public class SqlComparator {
    private static Logger log = Logger.getLogger(SqlComparator.class);
    
    public void compare() {
        Connection conn = null;
        Statement stmt = null;

        try {
            Class.forName(DBParam.Driver).newInstance();
            Properties pro = new Properties();
            pro.setProperty("user", DBParam.User);
            pro.setProperty("password", DBParam.Pswd);

            conn = DriverManager.getConnection(DBParam.DbUrl, pro);
            stmt = conn.createStatement();

            //compareUsingMap(stmt);
            
            compareUsingList(stmt);
        } catch (Exception e) {
            System.out.print(e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                log.error("Can't close stmt/conn because of " + e.getMessage());
            }
        }
    }
    

    private void compareUsingMap(Statement stmt) throws SQLException {
        long startMs = System.currentTimeMillis();
        Map<String,DhItem> leftMap=getMapFrom(getLeftjoinSql(),stmt);
        long endMs = System.currentTimeMillis();
        log.info("It takes "+ms2DHMS(startMs,endMs)+" to get leftMap.");
        int leftCount=leftMap.size();
        log.info("There are "+toEastNumFormat(leftCount)+" records in leftMap.");
        
        startMs = System.currentTimeMillis();
        Map<String,DhItem> notexistMap=getMapFrom(getNotExistSql(),stmt);
        endMs = System.currentTimeMillis();
        log.info("It takes "+ms2DHMS(startMs,endMs)+" to get notexistMap.");
        int notexistCount=notexistMap.size();
        log.info("There are "+toEastNumFormat(notexistCount)+" records in notexistMap.");
        
        startMs = System.currentTimeMillis();
        List<DhItem> onlyInInnerLs=new ArrayList<DhItem>();
        int count=0;
        for(String key:notexistMap.keySet()) {
            if(leftMap.containsKey(key)) {
                count++;
            }else {
                DhItem dhItem=notexistMap.get(key);
                onlyInInnerLs.add(dhItem);
            }
        }
        
        log.info("There are "+toEastNumFormat(count)+" records in two maps.");
        log.info("There are "+toEastNumFormat(onlyInInnerLs.size())+" records only in notexistMap.");
        endMs = System.currentTimeMillis();
        log.info("It takes "+ms2DHMS(startMs,endMs)+" to complete comparison using map.");
    }
    
    private void compareUsingList(Statement stmt) throws SQLException {
        long startMs = System.currentTimeMillis();
        List<DhItem> leftList=getListFrom(getLeftjoinSql(),stmt);
        long endMs = System.currentTimeMillis();
        log.info("It takes "+ms2DHMS(startMs,endMs)+" to get leftList.");
        int leftCount=leftList.size();
        log.info("There are "+toEastNumFormat(leftCount)+" records in leftList.");
        
        startMs = System.currentTimeMillis();
        List<DhItem> notexistList=getListFrom(getNotExistSql(),stmt);
        endMs = System.currentTimeMillis();
        log.info("It takes "+ms2DHMS(startMs,endMs)+" to get notexistList.");
        int notexistCount=notexistList.size();
        log.info("There are "+toEastNumFormat(notexistCount)+" records in notexistList.");
        
        startMs = System.currentTimeMillis();
        List<DhItem> onlyInInnerLs=new ArrayList<DhItem>();
        int count=0;
        for(DhItem item:notexistList) {
            if(leftList.contains(item)) {
                count++;
            }else {
                onlyInInnerLs.add(item);
            }
        }
        
        log.info("There are "+toEastNumFormat(count)+" records in two lists.");
        log.info("There are "+toEastNumFormat(onlyInInnerLs.size())+" records only in notexistList.");
        endMs = System.currentTimeMillis();
        log.info("It takes "+ms2DHMS(startMs,endMs)+" to complete comparison using list.");
    }
    
    
    private List<DhItem> getListFrom(String sql,Statement stmt) throws SQLException {
        List<DhItem> list=new ArrayList<DhItem>();
        
        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next()) {
            DhItem dhItem=new DhItem();
            dhItem.order_no=rs.getString("order_no");
            dhItem.shipper_code=rs.getString("shipper_code");
            dhItem.vehicle_name=rs.getString("vehicle_name");
            dhItem.vehicle_code=rs.getString("vehicle_code");
            dhItem.reason_name_mobile=rs.getString("reason_name_mobile");
            dhItem.status_name_mobile=rs.getString("status_name_mobile");
            list.add(dhItem);
        }
        
        return list;
    }
    
    private Map<String,DhItem> getMapFrom(String sql,Statement stmt) throws SQLException {
        Map<String,DhItem> map=new HashMap<String,DhItem>();
        
        ResultSet rs = stmt.executeQuery(sql);
        while (rs.next()) {
            DhItem dhItem=new DhItem();
            dhItem.order_no=rs.getString("order_no");
            dhItem.shipper_code=rs.getString("shipper_code");
            dhItem.vehicle_name=rs.getString("vehicle_name");
            dhItem.vehicle_code=rs.getString("vehicle_code");
            dhItem.reason_name_mobile=rs.getString("reason_name_mobile");
            dhItem.status_name_mobile=rs.getString("status_name_mobile");
            map.put(toMD5(dhItem.toString()), dhItem);
        }
        
        return map;
    }
    
    
    private String getLeftjoinSql() {
        StringBuilder sb = new StringBuilder();
        sb.append("     SELECT                                              ");
        sb.append("      DH1.ORDER_NO,                                   ");
        sb.append("      DH1.SHIPPER_CODE ,                              ");
        sb.append("      DH1.VEHICLE_NAME,                               ");
        sb.append("      DH1.VEHICLE_CODE ,                              ");
        sb.append("      DH1.REASON_NAME_MOBILE,                         ");
        sb.append("      DH1.STATUS_NAME_MOBILE                          ");
        sb.append("  from                                                ");
        sb.append("      DELIVERY_HISTORY DH1                            ");
        sb.append("      left JOIN DELIVERY_HISTORY DH2 on               ");
        sb.append("      DH1.SHIPPER_CODE = DH2.SHIPPER_CODE             ");
        sb.append("      and DH1.ORDER_NO = DH2.ORDER_NO                 ");
        sb.append("      and DH2.UPDATED_DATETIME > DH1.UPDATED_DATETIME ");
        sb.append("  where DH2.UPDATED_DATETIME IS NULL                  ");
        sb.append("      and DH1.DISABLED_FLG = 0                        ");
        String sql = sb.toString();
        return sql;
    }
    
    private String getInnerSql() {
        StringBuilder sb = new StringBuilder();
        sb.append("    select   ");
        sb.append("      DH1.ORDER_NO,                                   ");
        sb.append("      DH1.SHIPPER_CODE ,                              ");
        sb.append("      DH1.VEHICLE_NAME,                               ");
        sb.append("      DH1.VEHICLE_CODE ,                              ");
        sb.append("      DH1.REASON_NAME_MOBILE,                         ");
        sb.append("      DH1.STATUS_NAME_MOBILE                          ");
        sb.append("  from                                                                                      ");
        sb.append("         DELIVERY_HISTORY dh1 ,                                                                ");
        sb.append("         (select SHIPPER_CODE,ORDER_NO,max(UPDATED_DATETIME) as utime  from DELIVERY_HISTORY   ");
        sb.append("             group by SHIPPER_CODE,ORDER_NO) dh2                                               ");
        sb.append("     where                                                                                     ");
        sb.append("         dh1.SHIPPER_CODE=dh2.SHIPPER_CODE and                                                 ");
        sb.append("         dh1.ORDER_NO=dh2.ORDER_NO and                                                         ");
        sb.append("         dh1.UPDATED_DATETIME=dh2.utime and                                                    ");
        sb.append("         dh1.DISABLED_FLG='0'                                                                  ");

        String sql = sb.toString();
        
        return sql;
    }
    
    private String getNotExistSql() {
        StringBuilder sb = new StringBuilder();
        sb.append("    select ");
        sb.append("          a.ORDER_NO,         ");                          
        sb.append("          a.SHIPPER_CODE ,     ");                         
        sb.append("          a.VEHICLE_NAME,          ");                     
        sb.append("          a.VEHICLE_CODE ,             ");                 
        sb.append("          a.REASON_NAME_MOBILE,         ");                
        sb.append("          a.STATUS_NAME_MOBILE ,");
        sb.append("          a.UPDATED_DATETIME");
        sb.append("    from DELIVERY_HISTORY a");
        sb.append("    where not exists(select 1 ");
        sb.append("    from DELIVERY_HISTORY b");
        sb.append("    where b.SHIPPER_CODE=a.SHIPPER_CODE and b.ORDER_NO=a.ORDER_NO and b.UPDATED_DATETIME>a.UPDATED_DATETIME)");
        sb.append("         and  a.DISABLED_FLG=0                                                                  ");

        String sql = sb.toString();
        return sql;
    }
    
    // 将整数在万分位以逗号分隔表示
    public static String toEastNumFormat(long number) {
        DecimalFormat df = new DecimalFormat("#,####");
        return df.format(number);
    }
    
    /**
     * change seconds to DayHourMinuteSecond format
     * 
     * @param startMs
     * @param endMs
     * @return
     */
    private static String ms2DHMS(long startMs, long endMs) {
        String retval = null;
        long secondCount = (endMs - startMs) / 1000;
        String ms = (endMs - startMs) % 1000 + "ms";

        long days = secondCount / (60 * 60 * 24);
        long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
        long minutes = (secondCount % (60 * 60)) / 60;
        long seconds = secondCount % 60;

        if (days > 0) {
            retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
        } else if (hours > 0) {
            retval = hours + "h" + minutes + "m" + seconds + "s";
        } else if (minutes > 0) {
            retval = minutes + "m" + seconds + "s";
        } else {
            retval = seconds + "s";
        }

        return retval + ms;
    }
    
    public static String toMD5(String key) {
        char hexDigits[] = {
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
        };
        try {
            byte[] btInput = key.getBytes();
            // 获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            // 使用指定的字节更新摘要
            mdInst.update(btInput);
            // 获得密文
            byte[] md = mdInst.digest();
            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }
    
    
    public static void main(String[] args) {
        SqlComparator sc=new SqlComparator();
        sc.compare();
    }
}

输出:

2019-12-25 10:31:17,997  INFO [main] - It takes 2m36s81ms to get leftMap.
2019-12-25 10:31:18,002  INFO [main] - There are 35,7282 records in leftMap.
2019-12-25 10:33:57,147  INFO [main] - It takes 2m39s145ms to get notexistMap.
2019-12-25 10:33:57,147  INFO [main] - There are 35,7282 records in notexistMap.
2019-12-25 10:33:57,247  INFO [main] - There are 35,7282 records in two maps.
2019-12-25 10:33:57,247  INFO [main] - There are 0 records only in notexistMap.
2019-12-25 10:33:57,248  INFO [main] - It takes 0s101ms to complete comparison using map.

2019-12-25 10:44:22,695  INFO [main] - It takes 2m36s52ms to get leftList.
2019-12-25 10:44:22,700  INFO [main] - There are 36,1396 records in leftList.
2019-12-25 10:46:55,335  INFO [main] - It takes 2m32s634ms to get notexistList.
2019-12-25 10:46:55,335  INFO [main] - There are 36,1396 records in notexistList.
2019-12-25 10:47:41,789  INFO [main] - There are 0 records in two lists.
2019-12-25 10:47:41,790  INFO [main] - There are 36,1396 records only in notexistList.
2019-12-25 10:47:41,790  INFO [main] - It takes 46s455ms to complete comparison using list.

--END-- 2019-12-25 11:45

原文地址:https://www.cnblogs.com/heyang78/p/12095121.html